isl_union_set_compute_schedule: fix computation of maximal number of rows
[platform/upstream/isl.git] / isl_schedule.c
1 /*
2  * Copyright 2011      INRIA Saclay
3  *
4  * Use of this software is governed by the GNU LGPLv2.1 license
5  *
6  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
8  * 91893 Orsay, France
9  */
10
11 #include <isl_ctx_private.h>
12 #include <isl_map_private.h>
13 #include <isl_space_private.h>
14 #include <isl/hash.h>
15 #include <isl/constraint.h>
16 #include <isl/schedule.h>
17 #include <isl_mat_private.h>
18 #include <isl/set.h>
19 #include <isl/seq.h>
20 #include <isl_tab.h>
21 #include <isl_dim_map.h>
22 #include <isl_hmap_map_basic_set.h>
23 #include <isl_qsort.h>
24 #include <isl_schedule_private.h>
25 #include <isl_band_private.h>
26 #include <isl_list_private.h>
27 #include <isl_options_private.h>
28
29 /*
30  * The scheduling algorithm implemented in this file was inspired by
31  * Bondhugula et al., "Automatic Transformations for Communication-Minimized
32  * Parallelization and Locality Optimization in the Polyhedral Model".
33  */
34
35
36 /* Internal information about a node that is used during the construction
37  * of a schedule.
38  * dim represents the space in which the domain lives
39  * sched is a matrix representation of the schedule being constructed
40  *      for this node
41  * sched_map is an isl_map representation of the same (partial) schedule
42  *      sched_map may be NULL
43  * rank is the number of linearly independent rows in the linear part
44  *      of sched
45  * the columns of cmap represent a change of basis for the schedule
46  *      coefficients; the first rank columns span the linear part of
47  *      the schedule rows
48  * start is the first variable in the LP problem in the sequences that
49  *      represents the schedule coefficients of this node
50  * nvar is the dimension of the domain
51  * nparam is the number of parameters or 0 if we are not constructing
52  *      a parametric schedule
53  *
54  * scc is the index of SCC (or WCC) this node belongs to
55  *
56  * band contains the band index for each of the rows of the schedule.
57  * band_id is used to differentiate between separate bands at the same
58  * level within the same parent band, i.e., bands that are separated
59  * by the parent band or bands that are independent of each other.
60  * zero contains a boolean for each of the rows of the schedule,
61  * indicating whether the corresponding scheduling dimension results
62  * in zero dependence distances within its band and with respect
63  * to the proximity edges.
64  *
65  * index, min_index and on_stack are used during the SCC detection
66  * index represents the order in which nodes are visited.
67  * min_index is the index of the root of a (sub)component.
68  * on_stack indicates whether the node is currently on the stack.
69  */
70 struct isl_sched_node {
71         isl_space *dim;
72         isl_mat *sched;
73         isl_map *sched_map;
74         int      rank;
75         isl_mat *cmap;
76         int      start;
77         int      nvar;
78         int      nparam;
79
80         int      scc;
81
82         int     *band;
83         int     *band_id;
84         int     *zero;
85
86         /* scc detection */
87         int      index;
88         int      min_index;
89         int      on_stack;
90 };
91
92 static int node_has_dim(const void *entry, const void *val)
93 {
94         struct isl_sched_node *node = (struct isl_sched_node *)entry;
95         isl_space *dim = (isl_space *)val;
96
97         return isl_space_is_equal(node->dim, dim);
98 }
99
100 /* An edge in the dependence graph.  An edge may be used to
101  * ensure validity of the generated schedule, to minimize the dependence
102  * distance or both
103  *
104  * map is the dependence relation
105  * src is the source node
106  * dst is the sink node
107  * validity is set if the edge is used to ensure correctness
108  * proximity is set if the edge is used to minimize dependence distances
109  *
110  * For validity edges, start and end mark the sequence of inequality
111  * constraints in the LP problem that encode the validity constraint
112  * corresponding to this edge.
113  */
114 struct isl_sched_edge {
115         isl_map *map;
116
117         struct isl_sched_node *src;
118         struct isl_sched_node *dst;
119
120         int validity;
121         int proximity;
122
123         int start;
124         int end;
125 };
126
127 /* Internal information about the dependence graph used during
128  * the construction of the schedule.
129  *
130  * intra_hmap is a cache, mapping dependence relations to their dual,
131  *      for dependences from a node to itself
132  * inter_hmap is a cache, mapping dependence relations to their dual,
133  *      for dependences between distinct nodes
134  *
135  * n is the number of nodes
136  * node is the list of nodes
137  * maxvar is the maximal number of variables over all nodes
138  * max_row is the allocated number of rows in the schedule
139  * n_row is the current (maximal) number of linearly independent
140  *      rows in the node schedules
141  * n_total_row is the current number of rows in the node schedules
142  * n_band is the current number of completed bands
143  * band_start is the starting row in the node schedules of the current band
144  * root is set if this graph is the original dependence graph,
145  *      without any splitting
146  *
147  * sorted contains a list of node indices sorted according to the
148  *      SCC to which a node belongs
149  *
150  * n_edge is the number of edges
151  * edge is the list of edges
152  * edge_table contains pointers into the edge array, hashed on the source
153  *      and sink spaces; the table only contains edges that represent
154  *      validity constraints (and that may or may not also represent proximity
155  *      constraints)
156  *
157  * node_table contains pointers into the node array, hashed on the space
158  *
159  * region contains a list of variable sequences that should be non-trivial
160  *
161  * lp contains the (I)LP problem used to obtain new schedule rows
162  *
163  * src_scc and dst_scc are the source and sink SCCs of an edge with
164  *      conflicting constraints
165  *
166  * scc, sp, index and stack are used during the detection of SCCs
167  * scc is the number of the next SCC
168  * stack contains the nodes on the path from the root to the current node
169  * sp is the stack pointer
170  * index is the index of the last node visited
171  */
172 struct isl_sched_graph {
173         isl_hmap_map_basic_set *intra_hmap;
174         isl_hmap_map_basic_set *inter_hmap;
175
176         struct isl_sched_node *node;
177         int n;
178         int maxvar;
179         int max_row;
180         int n_row;
181
182         int *sorted;
183
184         int n_band;
185         int n_total_row;
186         int band_start;
187
188         int root;
189
190         struct isl_sched_edge *edge;
191         int n_edge;
192         struct isl_hash_table *edge_table;
193
194         struct isl_hash_table *node_table;
195         struct isl_region *region;
196
197         isl_basic_set *lp;
198
199         int src_scc;
200         int dst_scc;
201
202         /* scc detection */
203         int scc;
204         int sp;
205         int index;
206         int *stack;
207 };
208
209 /* Initialize node_table based on the list of nodes.
210  */
211 static int graph_init_table(isl_ctx *ctx, struct isl_sched_graph *graph)
212 {
213         int i;
214
215         graph->node_table = isl_hash_table_alloc(ctx, graph->n);
216         if (!graph->node_table)
217                 return -1;
218
219         for (i = 0; i < graph->n; ++i) {
220                 struct isl_hash_table_entry *entry;
221                 uint32_t hash;
222
223                 hash = isl_space_get_hash(graph->node[i].dim);
224                 entry = isl_hash_table_find(ctx, graph->node_table, hash,
225                                             &node_has_dim,
226                                             graph->node[i].dim, 1);
227                 if (!entry)
228                         return -1;
229                 entry->data = &graph->node[i];
230         }
231
232         return 0;
233 }
234
235 /* Return a pointer to the node that lives within the given space,
236  * or NULL if there is no such node.
237  */
238 static struct isl_sched_node *graph_find_node(isl_ctx *ctx,
239         struct isl_sched_graph *graph, __isl_keep isl_space *dim)
240 {
241         struct isl_hash_table_entry *entry;
242         uint32_t hash;
243
244         hash = isl_space_get_hash(dim);
245         entry = isl_hash_table_find(ctx, graph->node_table, hash,
246                                     &node_has_dim, dim, 0);
247
248         return entry ? entry->data : NULL;
249 }
250
251 static int edge_has_src_and_dst(const void *entry, const void *val)
252 {
253         const struct isl_sched_edge *edge = entry;
254         const struct isl_sched_edge *temp = val;
255
256         return edge->src == temp->src && edge->dst == temp->dst;
257 }
258
259 /* Initialize edge_table based on the list of edges.
260  * Only edges with validity set are added to the table.
261  */
262 static int graph_init_edge_table(isl_ctx *ctx, struct isl_sched_graph *graph)
263 {
264         int i;
265
266         graph->edge_table = isl_hash_table_alloc(ctx, graph->n_edge);
267         if (!graph->edge_table)
268                 return -1;
269
270         for (i = 0; i < graph->n_edge; ++i) {
271                 struct isl_hash_table_entry *entry;
272                 uint32_t hash;
273
274                 if (!graph->edge[i].validity)
275                         continue;
276
277                 hash = isl_hash_init();
278                 hash = isl_hash_builtin(hash, graph->edge[i].src);
279                 hash = isl_hash_builtin(hash, graph->edge[i].dst);
280                 entry = isl_hash_table_find(ctx, graph->edge_table, hash,
281                                             &edge_has_src_and_dst,
282                                             &graph->edge[i], 1);
283                 if (!entry)
284                         return -1;
285                 entry->data = &graph->edge[i];
286         }
287
288         return 0;
289 }
290
291 /* Check whether the dependence graph has a (validity) edge
292  * between the given two nodes.
293  */
294 static int graph_has_edge(struct isl_sched_graph *graph,
295         struct isl_sched_node *src, struct isl_sched_node *dst)
296 {
297         isl_ctx *ctx = isl_space_get_ctx(src->dim);
298         struct isl_hash_table_entry *entry;
299         uint32_t hash;
300         struct isl_sched_edge temp = { .src = src, .dst = dst };
301         struct isl_sched_edge *edge;
302         int empty;
303
304         hash = isl_hash_init();
305         hash = isl_hash_builtin(hash, temp.src);
306         hash = isl_hash_builtin(hash, temp.dst);
307         entry = isl_hash_table_find(ctx, graph->edge_table, hash,
308                                     &edge_has_src_and_dst, &temp, 0);
309         if (!entry)
310                 return 0;
311
312         edge = entry->data;
313         empty = isl_map_plain_is_empty(edge->map);
314         if (empty < 0)
315                 return -1;
316
317         return !empty;
318 }
319
320 static int graph_alloc(isl_ctx *ctx, struct isl_sched_graph *graph,
321         int n_node, int n_edge)
322 {
323         int i;
324
325         graph->n = n_node;
326         graph->n_edge = n_edge;
327         graph->node = isl_calloc_array(ctx, struct isl_sched_node, graph->n);
328         graph->sorted = isl_calloc_array(ctx, int, graph->n);
329         graph->region = isl_alloc_array(ctx, struct isl_region, graph->n);
330         graph->stack = isl_alloc_array(ctx, int, graph->n);
331         graph->edge = isl_calloc_array(ctx,
332                                         struct isl_sched_edge, graph->n_edge);
333
334         graph->intra_hmap = isl_hmap_map_basic_set_alloc(ctx, 2 * n_edge);
335         graph->inter_hmap = isl_hmap_map_basic_set_alloc(ctx, 2 * n_edge);
336
337         if (!graph->node || !graph->region || !graph->stack || !graph->edge ||
338             !graph->sorted)
339                 return -1;
340
341         for(i = 0; i < graph->n; ++i)
342                 graph->sorted[i] = i;
343
344         return 0;
345 }
346
347 static void graph_free(isl_ctx *ctx, struct isl_sched_graph *graph)
348 {
349         int i;
350
351         isl_hmap_map_basic_set_free(ctx, graph->intra_hmap);
352         isl_hmap_map_basic_set_free(ctx, graph->inter_hmap);
353
354         for (i = 0; i < graph->n; ++i) {
355                 isl_space_free(graph->node[i].dim);
356                 isl_mat_free(graph->node[i].sched);
357                 isl_map_free(graph->node[i].sched_map);
358                 isl_mat_free(graph->node[i].cmap);
359                 if (graph->root) {
360                         free(graph->node[i].band);
361                         free(graph->node[i].band_id);
362                         free(graph->node[i].zero);
363                 }
364         }
365         free(graph->node);
366         free(graph->sorted);
367         for (i = 0; i < graph->n_edge; ++i)
368                 isl_map_free(graph->edge[i].map);
369         free(graph->edge);
370         free(graph->region);
371         free(graph->stack);
372         isl_hash_table_free(ctx, graph->edge_table);
373         isl_hash_table_free(ctx, graph->node_table);
374         isl_basic_set_free(graph->lp);
375 }
376
377 /* For each "set" on which this function is called, increment
378  * graph->n by one and update graph->maxvar.
379  */
380 static int init_n_maxvar(__isl_take isl_set *set, void *user)
381 {
382         struct isl_sched_graph *graph = user;
383         int nvar = isl_set_dim(set, isl_dim_set);
384
385         graph->n++;
386         if (nvar > graph->maxvar)
387                 graph->maxvar = nvar;
388
389         isl_set_free(set);
390
391         return 0;
392 }
393
394 /* Compute the number of rows that should be allocated for the schedule.
395  * The graph can be split at most "n - 1" times, there can be at most
396  * two rows for each dimension in the iteration domains (in particular,
397  * we usually have one row, but it may be split by split_parallel),
398  * and there can be one extra row for ordering the statements.
399  * Note that if we have actually split "n - 1" times, then no ordering
400  * is needed, so in principle we could use "graph->n + 2 * graph->maxvar - 1".
401  */
402 static int compute_max_row(struct isl_sched_graph *graph,
403         __isl_keep isl_union_set *domain)
404 {
405         graph->n = 0;
406         graph->maxvar = 0;
407         if (isl_union_set_foreach_set(domain, &init_n_maxvar, graph) < 0)
408                 return -1;
409         graph->max_row = graph->n + 2 * graph->maxvar;
410
411         return 0;
412 }
413
414 /* Add a new node to the graph representing the given set.
415  */
416 static int extract_node(__isl_take isl_set *set, void *user)
417 {
418         int nvar, nparam;
419         isl_ctx *ctx;
420         isl_space *dim;
421         isl_mat *sched;
422         struct isl_sched_graph *graph = user;
423         int *band, *band_id, *zero;
424
425         ctx = isl_set_get_ctx(set);
426         dim = isl_set_get_space(set);
427         isl_set_free(set);
428         nvar = isl_space_dim(dim, isl_dim_set);
429         nparam = isl_space_dim(dim, isl_dim_param);
430         if (!ctx->opt->schedule_parametric)
431                 nparam = 0;
432         sched = isl_mat_alloc(ctx, 0, 1 + nparam + nvar);
433         graph->node[graph->n].dim = dim;
434         graph->node[graph->n].nvar = nvar;
435         graph->node[graph->n].nparam = nparam;
436         graph->node[graph->n].sched = sched;
437         graph->node[graph->n].sched_map = NULL;
438         band = isl_alloc_array(ctx, int, graph->max_row);
439         graph->node[graph->n].band = band;
440         band_id = isl_calloc_array(ctx, int, graph->max_row);
441         graph->node[graph->n].band_id = band_id;
442         zero = isl_calloc_array(ctx, int, graph->max_row);
443         graph->node[graph->n].zero = zero;
444         graph->n++;
445
446         if (!sched || !band || !band_id || !zero)
447                 return -1;
448
449         return 0;
450 }
451
452 /* Add a new edge to the graph based on the given map.
453  * Edges are first extracted from the validity dependences,
454  * from which the edge_table is constructed.
455  * Afterwards, the proximity dependences are added.  If a proximity
456  * dependence relation happens to be identical to one of the
457  * validity dependence relations added before, then we don't create
458  * a new edge, but instead mark the original edge as also representing
459  * a proximity dependence.
460  */
461 static int extract_edge(__isl_take isl_map *map, void *user)
462 {
463         isl_ctx *ctx = isl_map_get_ctx(map);
464         struct isl_sched_graph *graph = user;
465         struct isl_sched_node *src, *dst;
466         isl_space *dim;
467
468         dim = isl_space_domain(isl_map_get_space(map));
469         src = graph_find_node(ctx, graph, dim);
470         isl_space_free(dim);
471         dim = isl_space_range(isl_map_get_space(map));
472         dst = graph_find_node(ctx, graph, dim);
473         isl_space_free(dim);
474
475         if (!src || !dst) {
476                 isl_map_free(map);
477                 return 0;
478         }
479
480         graph->edge[graph->n_edge].src = src;
481         graph->edge[graph->n_edge].dst = dst;
482         graph->edge[graph->n_edge].map = map;
483         graph->edge[graph->n_edge].validity = !graph->edge_table;
484         graph->edge[graph->n_edge].proximity = !!graph->edge_table;
485         graph->n_edge++;
486
487         if (graph->edge_table) {
488                 uint32_t hash;
489                 struct isl_hash_table_entry *entry;
490                 struct isl_sched_edge *edge;
491                 int is_equal;
492
493                 hash = isl_hash_init();
494                 hash = isl_hash_builtin(hash, src);
495                 hash = isl_hash_builtin(hash, dst);
496                 entry = isl_hash_table_find(ctx, graph->edge_table, hash,
497                                             &edge_has_src_and_dst,
498                                             &graph->edge[graph->n_edge - 1], 0);
499                 if (!entry)
500                         return 0;
501                 edge = entry->data;
502                 is_equal = isl_map_plain_is_equal(map, edge->map);
503                 if (is_equal < 0)
504                         return -1;
505                 if (!is_equal)
506                         return 0;
507
508                 graph->n_edge--;
509                 edge->proximity = 1;
510                 isl_map_free(map);
511         }
512
513         return 0;
514 }
515
516 /* Check whether there is a validity dependence from src to dst,
517  * forcing dst to follow src.
518  */
519 static int node_follows(struct isl_sched_graph *graph, 
520         struct isl_sched_node *dst, struct isl_sched_node *src)
521 {
522         return graph_has_edge(graph, src, dst);
523 }
524
525 /* Perform Tarjan's algorithm for computing the strongly connected components
526  * in the dependence graph (only validity edges).
527  * If directed is not set, we consider the graph to be undirected and
528  * we effectively compute the (weakly) connected components.
529  */
530 static int detect_sccs_tarjan(struct isl_sched_graph *g, int i, int directed)
531 {
532         int j;
533
534         g->node[i].index = g->index;
535         g->node[i].min_index = g->index;
536         g->node[i].on_stack = 1;
537         g->index++;
538         g->stack[g->sp++] = i;
539
540         for (j = g->n - 1; j >= 0; --j) {
541                 int f;
542
543                 if (j == i)
544                         continue;
545                 if (g->node[j].index >= 0 &&
546                         (!g->node[j].on_stack ||
547                          g->node[j].index > g->node[i].min_index))
548                         continue;
549                 
550                 f = node_follows(g, &g->node[i], &g->node[j]);
551                 if (f < 0)
552                         return -1;
553                 if (!f && !directed) {
554                         f = node_follows(g, &g->node[j], &g->node[i]);
555                         if (f < 0)
556                                 return -1;
557                 }
558                 if (!f)
559                         continue;
560                 if (g->node[j].index < 0) {
561                         detect_sccs_tarjan(g, j, directed);
562                         if (g->node[j].min_index < g->node[i].min_index)
563                                 g->node[i].min_index = g->node[j].min_index;
564                 } else if (g->node[j].index < g->node[i].min_index)
565                         g->node[i].min_index = g->node[j].index;
566         }
567
568         if (g->node[i].index != g->node[i].min_index)
569                 return 0;
570
571         do {
572                 j = g->stack[--g->sp];
573                 g->node[j].on_stack = 0;
574                 g->node[j].scc = g->scc;
575         } while (j != i);
576         g->scc++;
577
578         return 0;
579 }
580
581 static int detect_ccs(struct isl_sched_graph *graph, int directed)
582 {
583         int i;
584
585         graph->index = 0;
586         graph->sp = 0;
587         graph->scc = 0;
588         for (i = graph->n - 1; i >= 0; --i)
589                 graph->node[i].index = -1;
590
591         for (i = graph->n - 1; i >= 0; --i) {
592                 if (graph->node[i].index >= 0)
593                         continue;
594                 if (detect_sccs_tarjan(graph, i, directed) < 0)
595                         return -1;
596         }
597
598         return 0;
599 }
600
601 /* Apply Tarjan's algorithm to detect the strongly connected components
602  * in the dependence graph.
603  */
604 static int detect_sccs(struct isl_sched_graph *graph)
605 {
606         return detect_ccs(graph, 1);
607 }
608
609 /* Apply Tarjan's algorithm to detect the (weakly) connected components
610  * in the dependence graph.
611  */
612 static int detect_wccs(struct isl_sched_graph *graph)
613 {
614         return detect_ccs(graph, 0);
615 }
616
617 static int cmp_scc(const void *a, const void *b, void *data)
618 {
619         struct isl_sched_graph *graph = data;
620         const int *i1 = a;
621         const int *i2 = b;
622
623         return graph->node[*i1].scc - graph->node[*i2].scc;
624 }
625
626 /* Sort the elements of graph->sorted according to the corresponding SCCs.
627  */
628 static void sort_sccs(struct isl_sched_graph *graph)
629 {
630         isl_quicksort(graph->sorted, graph->n, sizeof(int), &cmp_scc, graph);
631 }
632
633 /* Given a dependence relation R from a node to itself,
634  * construct the set of coefficients of valid constraints for elements
635  * in that dependence relation.
636  * In particular, the result contains tuples of coefficients
637  * c_0, c_n, c_x such that
638  *
639  *      c_0 + c_n n + c_x y - c_x x >= 0 for each (x,y) in R
640  *
641  * or, equivalently,
642  *
643  *      c_0 + c_n n + c_x d >= 0 for each d in delta R = { y - x | (x,y) in R }
644  *
645  * We choose here to compute the dual of delta R.
646  * Alternatively, we could have computed the dual of R, resulting
647  * in a set of tuples c_0, c_n, c_x, c_y, and then
648  * plugged in (c_0, c_n, c_x, -c_x).
649  */
650 static __isl_give isl_basic_set *intra_coefficients(
651         struct isl_sched_graph *graph, __isl_take isl_map *map)
652 {
653         isl_ctx *ctx = isl_map_get_ctx(map);
654         isl_set *delta;
655         isl_basic_set *coef;
656
657         if (isl_hmap_map_basic_set_has(ctx, graph->intra_hmap, map))
658                 return isl_hmap_map_basic_set_get(ctx, graph->intra_hmap, map);
659
660         delta = isl_set_remove_divs(isl_map_deltas(isl_map_copy(map)));
661         coef = isl_set_coefficients(delta);
662         isl_hmap_map_basic_set_set(ctx, graph->intra_hmap, map,
663                                         isl_basic_set_copy(coef));
664
665         return coef;
666 }
667
668 /* Given a dependence relation R, * construct the set of coefficients
669  * of valid constraints for elements in that dependence relation.
670  * In particular, the result contains tuples of coefficients
671  * c_0, c_n, c_x, c_y such that
672  *
673  *      c_0 + c_n n + c_x x + c_y y >= 0 for each (x,y) in R
674  *
675  */
676 static __isl_give isl_basic_set *inter_coefficients(
677         struct isl_sched_graph *graph, __isl_take isl_map *map)
678 {
679         isl_ctx *ctx = isl_map_get_ctx(map);
680         isl_set *set;
681         isl_basic_set *coef;
682
683         if (isl_hmap_map_basic_set_has(ctx, graph->inter_hmap, map))
684                 return isl_hmap_map_basic_set_get(ctx, graph->inter_hmap, map);
685
686         set = isl_map_wrap(isl_map_remove_divs(isl_map_copy(map)));
687         coef = isl_set_coefficients(set);
688         isl_hmap_map_basic_set_set(ctx, graph->inter_hmap, map,
689                                         isl_basic_set_copy(coef));
690
691         return coef;
692 }
693
694 /* Add constraints to graph->lp that force validity for the given
695  * dependence from a node i to itself.
696  * That is, add constraints that enforce
697  *
698  *      (c_i_0 + c_i_n n + c_i_x y) - (c_i_0 + c_i_n n + c_i_x x)
699  *      = c_i_x (y - x) >= 0
700  *
701  * for each (x,y) in R.
702  * We obtain general constraints on coefficients (c_0, c_n, c_x)
703  * of valid constraints for (y - x) and then plug in (0, 0, c_i_x^+ - c_i_x^-),
704  * where c_i_x = c_i_x^+ - c_i_x^-, with c_i_x^+ and c_i_x^- non-negative.
705  * In graph->lp, the c_i_x^- appear before their c_i_x^+ counterpart.
706  *
707  * Actually, we do not construct constraints for the c_i_x themselves,
708  * but for the coefficients of c_i_x written as a linear combination
709  * of the columns in node->cmap.
710  */
711 static int add_intra_validity_constraints(struct isl_sched_graph *graph,
712         struct isl_sched_edge *edge)
713 {
714         unsigned total;
715         isl_map *map = isl_map_copy(edge->map);
716         isl_ctx *ctx = isl_map_get_ctx(map);
717         isl_space *dim;
718         isl_dim_map *dim_map;
719         isl_basic_set *coef;
720         struct isl_sched_node *node = edge->src;
721
722         coef = intra_coefficients(graph, map);
723
724         dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
725
726         coef = isl_basic_set_transform_dims(coef, isl_dim_set,
727                     isl_space_dim(dim, isl_dim_set), isl_mat_copy(node->cmap));
728
729         total = isl_basic_set_total_dim(graph->lp);
730         dim_map = isl_dim_map_alloc(ctx, total);
731         isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
732                           isl_space_dim(dim, isl_dim_set), 1,
733                           node->nvar, -1);
734         isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
735                           isl_space_dim(dim, isl_dim_set), 1,
736                           node->nvar, 1);
737         graph->lp = isl_basic_set_extend_constraints(graph->lp,
738                         coef->n_eq, coef->n_ineq);
739         graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
740                                                            coef, dim_map);
741         isl_space_free(dim);
742
743         return 0;
744 }
745
746 /* Add constraints to graph->lp that force validity for the given
747  * dependence from node i to node j.
748  * That is, add constraints that enforce
749  *
750  *      (c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) >= 0
751  *
752  * for each (x,y) in R.
753  * We obtain general constraints on coefficients (c_0, c_n, c_x, c_y)
754  * of valid constraints for R and then plug in
755  * (c_j_0 - c_i_0, c_j_n^+ - c_j_n^- - (c_i_n^+ - c_i_n^-),
756  *  c_j_x^+ - c_j_x^- - (c_i_x^+ - c_i_x^-)),
757  * where c_* = c_*^+ - c_*^-, with c_*^+ and c_*^- non-negative.
758  * In graph->lp, the c_*^- appear before their c_*^+ counterpart.
759  *
760  * Actually, we do not construct constraints for the c_*_x themselves,
761  * but for the coefficients of c_*_x written as a linear combination
762  * of the columns in node->cmap.
763  */
764 static int add_inter_validity_constraints(struct isl_sched_graph *graph,
765         struct isl_sched_edge *edge)
766 {
767         unsigned total;
768         isl_map *map = isl_map_copy(edge->map);
769         isl_ctx *ctx = isl_map_get_ctx(map);
770         isl_space *dim;
771         isl_dim_map *dim_map;
772         isl_basic_set *coef;
773         struct isl_sched_node *src = edge->src;
774         struct isl_sched_node *dst = edge->dst;
775
776         coef = inter_coefficients(graph, map);
777
778         dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
779
780         coef = isl_basic_set_transform_dims(coef, isl_dim_set,
781                     isl_space_dim(dim, isl_dim_set), isl_mat_copy(src->cmap));
782         coef = isl_basic_set_transform_dims(coef, isl_dim_set,
783                     isl_space_dim(dim, isl_dim_set) + src->nvar,
784                     isl_mat_copy(dst->cmap));
785
786         total = isl_basic_set_total_dim(graph->lp);
787         dim_map = isl_dim_map_alloc(ctx, total);
788
789         isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, 1);
790         isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, -1);
791         isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, 1);
792         isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
793                           isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
794                           dst->nvar, -1);
795         isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
796                           isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
797                           dst->nvar, 1);
798
799         isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, -1);
800         isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, 1);
801         isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, -1);
802         isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
803                           isl_space_dim(dim, isl_dim_set), 1,
804                           src->nvar, 1);
805         isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
806                           isl_space_dim(dim, isl_dim_set), 1,
807                           src->nvar, -1);
808
809         edge->start = graph->lp->n_ineq;
810         graph->lp = isl_basic_set_extend_constraints(graph->lp,
811                         coef->n_eq, coef->n_ineq);
812         graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
813                                                            coef, dim_map);
814         isl_space_free(dim);
815         edge->end = graph->lp->n_ineq;
816
817         return 0;
818 }
819
820 /* Add constraints to graph->lp that bound the dependence distance for the given
821  * dependence from a node i to itself.
822  * If s = 1, we add the constraint
823  *
824  *      c_i_x (y - x) <= m_0 + m_n n
825  *
826  * or
827  *
828  *      -c_i_x (y - x) + m_0 + m_n n >= 0
829  *
830  * for each (x,y) in R.
831  * If s = -1, we add the constraint
832  *
833  *      -c_i_x (y - x) <= m_0 + m_n n
834  *
835  * or
836  *
837  *      c_i_x (y - x) + m_0 + m_n n >= 0
838  *
839  * for each (x,y) in R.
840  * We obtain general constraints on coefficients (c_0, c_n, c_x)
841  * of valid constraints for (y - x) and then plug in (m_0, m_n, -s * c_i_x),
842  * with each coefficient (except m_0) represented as a pair of non-negative
843  * coefficients.
844  *
845  * Actually, we do not construct constraints for the c_i_x themselves,
846  * but for the coefficients of c_i_x written as a linear combination
847  * of the columns in node->cmap.
848  */
849 static int add_intra_proximity_constraints(struct isl_sched_graph *graph,
850         struct isl_sched_edge *edge, int s)
851 {
852         unsigned total;
853         unsigned nparam;
854         isl_map *map = isl_map_copy(edge->map);
855         isl_ctx *ctx = isl_map_get_ctx(map);
856         isl_space *dim;
857         isl_dim_map *dim_map;
858         isl_basic_set *coef;
859         struct isl_sched_node *node = edge->src;
860
861         coef = intra_coefficients(graph, map);
862
863         dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
864
865         coef = isl_basic_set_transform_dims(coef, isl_dim_set,
866                     isl_space_dim(dim, isl_dim_set), isl_mat_copy(node->cmap));
867
868         nparam = isl_space_dim(node->dim, isl_dim_param);
869         total = isl_basic_set_total_dim(graph->lp);
870         dim_map = isl_dim_map_alloc(ctx, total);
871         isl_dim_map_range(dim_map, 1, 0, 0, 0, 1, 1);
872         isl_dim_map_range(dim_map, 4, 2, 1, 1, nparam, -1);
873         isl_dim_map_range(dim_map, 5, 2, 1, 1, nparam, 1);
874         isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
875                           isl_space_dim(dim, isl_dim_set), 1,
876                           node->nvar, s);
877         isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
878                           isl_space_dim(dim, isl_dim_set), 1,
879                           node->nvar, -s);
880         graph->lp = isl_basic_set_extend_constraints(graph->lp,
881                         coef->n_eq, coef->n_ineq);
882         graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
883                                                            coef, dim_map);
884         isl_space_free(dim);
885
886         return 0;
887 }
888
889 /* Add constraints to graph->lp that bound the dependence distance for the given
890  * dependence from node i to node j.
891  * If s = 1, we add the constraint
892  *
893  *      (c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x)
894  *              <= m_0 + m_n n
895  *
896  * or
897  *
898  *      -(c_j_0 + c_j_n n + c_j_x y) + (c_i_0 + c_i_n n + c_i_x x) +
899  *              m_0 + m_n n >= 0
900  *
901  * for each (x,y) in R.
902  * If s = -1, we add the constraint
903  *
904  *      -((c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x))
905  *              <= m_0 + m_n n
906  *
907  * or
908  *
909  *      (c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) +
910  *              m_0 + m_n n >= 0
911  *
912  * for each (x,y) in R.
913  * We obtain general constraints on coefficients (c_0, c_n, c_x, c_y)
914  * of valid constraints for R and then plug in
915  * (m_0 - s*c_j_0 + s*c_i_0, m_n - s*c_j_n + s*c_i_n,
916  *  -s*c_j_x+s*c_i_x)
917  * with each coefficient (except m_0, c_j_0 and c_i_0)
918  * represented as a pair of non-negative coefficients.
919  *
920  * Actually, we do not construct constraints for the c_*_x themselves,
921  * but for the coefficients of c_*_x written as a linear combination
922  * of the columns in node->cmap.
923  */
924 static int add_inter_proximity_constraints(struct isl_sched_graph *graph,
925         struct isl_sched_edge *edge, int s)
926 {
927         unsigned total;
928         unsigned nparam;
929         isl_map *map = isl_map_copy(edge->map);
930         isl_ctx *ctx = isl_map_get_ctx(map);
931         isl_space *dim;
932         isl_dim_map *dim_map;
933         isl_basic_set *coef;
934         struct isl_sched_node *src = edge->src;
935         struct isl_sched_node *dst = edge->dst;
936
937         coef = inter_coefficients(graph, map);
938
939         dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
940
941         coef = isl_basic_set_transform_dims(coef, isl_dim_set,
942                     isl_space_dim(dim, isl_dim_set), isl_mat_copy(src->cmap));
943         coef = isl_basic_set_transform_dims(coef, isl_dim_set,
944                     isl_space_dim(dim, isl_dim_set) + src->nvar,
945                     isl_mat_copy(dst->cmap));
946
947         nparam = isl_space_dim(src->dim, isl_dim_param);
948         total = isl_basic_set_total_dim(graph->lp);
949         dim_map = isl_dim_map_alloc(ctx, total);
950
951         isl_dim_map_range(dim_map, 1, 0, 0, 0, 1, 1);
952         isl_dim_map_range(dim_map, 4, 2, 1, 1, nparam, -1);
953         isl_dim_map_range(dim_map, 5, 2, 1, 1, nparam, 1);
954
955         isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, -s);
956         isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, s);
957         isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, -s);
958         isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
959                           isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
960                           dst->nvar, s);
961         isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
962                           isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
963                           dst->nvar, -s);
964
965         isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, s);
966         isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, -s);
967         isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, s);
968         isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
969                           isl_space_dim(dim, isl_dim_set), 1,
970                           src->nvar, -s);
971         isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
972                           isl_space_dim(dim, isl_dim_set), 1,
973                           src->nvar, s);
974
975         graph->lp = isl_basic_set_extend_constraints(graph->lp,
976                         coef->n_eq, coef->n_ineq);
977         graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
978                                                            coef, dim_map);
979         isl_space_free(dim);
980
981         return 0;
982 }
983
984 static int add_all_validity_constraints(struct isl_sched_graph *graph)
985 {
986         int i;
987
988         for (i = 0; i < graph->n_edge; ++i) {
989                 struct isl_sched_edge *edge= &graph->edge[i];
990                 if (!edge->validity)
991                         continue;
992                 if (edge->src != edge->dst)
993                         continue;
994                 if (add_intra_validity_constraints(graph, edge) < 0)
995                         return -1;
996         }
997
998         for (i = 0; i < graph->n_edge; ++i) {
999                 struct isl_sched_edge *edge = &graph->edge[i];
1000                 if (!edge->validity)
1001                         continue;
1002                 if (edge->src == edge->dst)
1003                         continue;
1004                 if (add_inter_validity_constraints(graph, edge) < 0)
1005                         return -1;
1006         }
1007
1008         return 0;
1009 }
1010
1011 /* Add constraints to graph->lp that bound the dependence distance
1012  * for all dependence relations.
1013  * If a given proximity dependence is identical to a validity
1014  * dependence, then the dependence distance is already bounded
1015  * from below (by zero), so we only need to bound the distance
1016  * from above.
1017  * Otherwise, we need to bound the distance both from above and from below.
1018  */
1019 static int add_all_proximity_constraints(struct isl_sched_graph *graph)
1020 {
1021         int i;
1022
1023         for (i = 0; i < graph->n_edge; ++i) {
1024                 struct isl_sched_edge *edge= &graph->edge[i];
1025                 if (!edge->proximity)
1026                         continue;
1027                 if (edge->src == edge->dst &&
1028                     add_intra_proximity_constraints(graph, edge, 1) < 0)
1029                         return -1;
1030                 if (edge->src != edge->dst &&
1031                     add_inter_proximity_constraints(graph, edge, 1) < 0)
1032                         return -1;
1033                 if (edge->validity)
1034                         continue;
1035                 if (edge->src == edge->dst &&
1036                     add_intra_proximity_constraints(graph, edge, -1) < 0)
1037                         return -1;
1038                 if (edge->src != edge->dst &&
1039                     add_inter_proximity_constraints(graph, edge, -1) < 0)
1040                         return -1;
1041         }
1042
1043         return 0;
1044 }
1045
1046 /* Compute a basis for the rows in the linear part of the schedule
1047  * and extend this basis to a full basis.  The remaining rows
1048  * can then be used to force linear independence from the rows
1049  * in the schedule.
1050  *
1051  * In particular, given the schedule rows S, we compute
1052  *
1053  *      S = H Q
1054  *
1055  * with H the Hermite normal form of S.  That is, all but the
1056  * first rank columns of Q are zero and so each row in S is
1057  * a linear combination of the first rank rows of Q.
1058  * The matrix Q is then transposed because we will write the
1059  * coefficients of the next schedule row as a column vector s
1060  * and express this s as a linear combination s = Q c of the
1061  * computed basis.
1062  */
1063 static int node_update_cmap(struct isl_sched_node *node)
1064 {
1065         isl_mat *H, *Q;
1066         int n_row = isl_mat_rows(node->sched);
1067
1068         H = isl_mat_sub_alloc(node->sched, 0, n_row,
1069                               1 + node->nparam, node->nvar);
1070
1071         H = isl_mat_left_hermite(H, 0, NULL, &Q);
1072         isl_mat_free(node->cmap);
1073         node->cmap = isl_mat_transpose(Q);
1074         node->rank = isl_mat_initial_non_zero_cols(H);
1075         isl_mat_free(H);
1076
1077         if (!node->cmap || node->rank < 0)
1078                 return -1;
1079         return 0;
1080 }
1081
1082 /* Count the number of equality and inequality constraints
1083  * that will be added for the given map.
1084  * If once is set, then we count
1085  * each edge exactly once.  Otherwise, we count as follows
1086  * validity             -> 1 (>= 0)
1087  * validity+proximity   -> 2 (>= 0 and upper bound)
1088  * proximity            -> 2 (lower and upper bound)
1089  */
1090 static int count_map_constraints(struct isl_sched_graph *graph,
1091         struct isl_sched_edge *edge, __isl_take isl_map *map,
1092         int *n_eq, int *n_ineq, int once)
1093 {
1094         isl_basic_set *coef;
1095         int f = once ? 1 : edge->proximity ? 2 : 1;
1096
1097         if (edge->src == edge->dst)
1098                 coef = intra_coefficients(graph, map);
1099         else
1100                 coef = inter_coefficients(graph, map);
1101         if (!coef)
1102                 return -1;
1103         *n_eq += f * coef->n_eq;
1104         *n_ineq += f * coef->n_ineq;
1105         isl_basic_set_free(coef);
1106
1107         return 0;
1108 }
1109
1110 /* Count the number of equality and inequality constraints
1111  * that will be added to the main lp problem.
1112  * If once is set, then we count
1113  * each edge exactly once.  Otherwise, we count as follows
1114  * validity             -> 1 (>= 0)
1115  * validity+proximity   -> 2 (>= 0 and upper bound)
1116  * proximity            -> 2 (lower and upper bound)
1117  */
1118 static int count_constraints(struct isl_sched_graph *graph,
1119         int *n_eq, int *n_ineq, int once)
1120 {
1121         int i;
1122
1123         *n_eq = *n_ineq = 0;
1124         for (i = 0; i < graph->n_edge; ++i) {
1125                 struct isl_sched_edge *edge= &graph->edge[i];
1126                 isl_map *map = isl_map_copy(edge->map);
1127
1128                 if (count_map_constraints(graph, edge, map,
1129                                           n_eq, n_ineq, once) < 0)
1130                         return -1;
1131         }
1132
1133         return 0;
1134 }
1135
1136 /* Construct an ILP problem for finding schedule coefficients
1137  * that result in non-negative, but small dependence distances
1138  * over all dependences.
1139  * In particular, the dependence distances over proximity edges
1140  * are bounded by m_0 + m_n n and we compute schedule coefficients
1141  * with small values (preferably zero) of m_n and m_0.
1142  *
1143  * All variables of the ILP are non-negative.  The actual coefficients
1144  * may be negative, so each coefficient is represented as the difference
1145  * of two non-negative variables.  The negative part always appears
1146  * immediately before the positive part.
1147  * Other than that, the variables have the following order
1148  *
1149  *      - sum of positive and negative parts of m_n coefficients
1150  *      - m_0
1151  *      - sum of positive and negative parts of all c_n coefficients
1152  *              (unconstrained when computing non-parametric schedules)
1153  *      - sum of positive and negative parts of all c_x coefficients
1154  *      - positive and negative parts of m_n coefficients
1155  *      - for each node
1156  *              - c_i_0
1157  *              - positive and negative parts of c_i_n (if parametric)
1158  *              - positive and negative parts of c_i_x
1159  *
1160  * The c_i_x are not represented directly, but through the columns of
1161  * node->cmap.  That is, the computed values are for variable t_i_x
1162  * such that c_i_x = Q t_i_x with Q equal to node->cmap.
1163  *
1164  * The constraints are those from the edges plus two or three equalities
1165  * to express the sums.
1166  *
1167  * If force_zero is set, then we add equalities to ensure that
1168  * the sum of the m_n coefficients and m_0 are both zero.
1169  */
1170 static int setup_lp(isl_ctx *ctx, struct isl_sched_graph *graph,
1171         int force_zero)
1172 {
1173         int i, j;
1174         int k;
1175         unsigned nparam;
1176         unsigned total;
1177         isl_space *dim;
1178         int parametric;
1179         int param_pos;
1180         int n_eq, n_ineq;
1181         int max_constant_term;
1182
1183         max_constant_term = ctx->opt->schedule_max_constant_term;
1184
1185         parametric = ctx->opt->schedule_parametric;
1186         nparam = isl_space_dim(graph->node[0].dim, isl_dim_param);
1187         param_pos = 4;
1188         total = param_pos + 2 * nparam;
1189         for (i = 0; i < graph->n; ++i) {
1190                 struct isl_sched_node *node = &graph->node[graph->sorted[i]];
1191                 if (node_update_cmap(node) < 0)
1192                         return -1;
1193                 node->start = total;
1194                 total += 1 + 2 * (node->nparam + node->nvar);
1195         }
1196
1197         if (count_constraints(graph, &n_eq, &n_ineq, 0) < 0)
1198                 return -1;
1199
1200         dim = isl_space_set_alloc(ctx, 0, total);
1201         isl_basic_set_free(graph->lp);
1202         n_eq += 2 + parametric + force_zero;
1203         if (max_constant_term != -1)
1204                 n_ineq += graph->n;
1205
1206         graph->lp = isl_basic_set_alloc_space(dim, 0, n_eq, n_ineq);
1207
1208         k = isl_basic_set_alloc_equality(graph->lp);
1209         if (k < 0)
1210                 return -1;
1211         isl_seq_clr(graph->lp->eq[k], 1 +  total);
1212         if (!force_zero)
1213                 isl_int_set_si(graph->lp->eq[k][1], -1);
1214         for (i = 0; i < 2 * nparam; ++i)
1215                 isl_int_set_si(graph->lp->eq[k][1 + param_pos + i], 1);
1216
1217         if (force_zero) {
1218                 k = isl_basic_set_alloc_equality(graph->lp);
1219                 if (k < 0)
1220                         return -1;
1221                 isl_seq_clr(graph->lp->eq[k], 1 +  total);
1222                 isl_int_set_si(graph->lp->eq[k][2], -1);
1223         }
1224
1225         if (parametric) {
1226                 k = isl_basic_set_alloc_equality(graph->lp);
1227                 if (k < 0)
1228                         return -1;
1229                 isl_seq_clr(graph->lp->eq[k], 1 +  total);
1230                 isl_int_set_si(graph->lp->eq[k][3], -1);
1231                 for (i = 0; i < graph->n; ++i) {
1232                         int pos = 1 + graph->node[i].start + 1;
1233
1234                         for (j = 0; j < 2 * graph->node[i].nparam; ++j)
1235                                 isl_int_set_si(graph->lp->eq[k][pos + j], 1);
1236                 }
1237         }
1238
1239         k = isl_basic_set_alloc_equality(graph->lp);
1240         if (k < 0)
1241                 return -1;
1242         isl_seq_clr(graph->lp->eq[k], 1 +  total);
1243         isl_int_set_si(graph->lp->eq[k][4], -1);
1244         for (i = 0; i < graph->n; ++i) {
1245                 struct isl_sched_node *node = &graph->node[i];
1246                 int pos = 1 + node->start + 1 + 2 * node->nparam;
1247
1248                 for (j = 0; j < 2 * node->nvar; ++j)
1249                         isl_int_set_si(graph->lp->eq[k][pos + j], 1);
1250         }
1251
1252         if (max_constant_term != -1)
1253                 for (i = 0; i < graph->n; ++i) {
1254                         struct isl_sched_node *node = &graph->node[i];
1255                         k = isl_basic_set_alloc_inequality(graph->lp);
1256                         if (k < 0)
1257                                 return -1;
1258                         isl_seq_clr(graph->lp->ineq[k], 1 +  total);
1259                         isl_int_set_si(graph->lp->ineq[k][1 + node->start], -1);
1260                         isl_int_set_si(graph->lp->ineq[k][0], max_constant_term);
1261                 }
1262
1263         if (add_all_validity_constraints(graph) < 0)
1264                 return -1;
1265         if (add_all_proximity_constraints(graph) < 0)
1266                 return -1;
1267
1268         return 0;
1269 }
1270
1271 /* Analyze the conflicting constraint found by
1272  * isl_tab_basic_set_non_trivial_lexmin.  If it corresponds to the validity
1273  * constraint of one of the edges between distinct nodes, living, moreover
1274  * in distinct SCCs, then record the source and sink SCC as this may
1275  * be a good place to cut between SCCs.
1276  */
1277 static int check_conflict(int con, void *user)
1278 {
1279         int i;
1280         struct isl_sched_graph *graph = user;
1281
1282         if (graph->src_scc >= 0)
1283                 return 0;
1284
1285         con -= graph->lp->n_eq;
1286
1287         if (con >= graph->lp->n_ineq)
1288                 return 0;
1289
1290         for (i = 0; i < graph->n_edge; ++i) {
1291                 if (!graph->edge[i].validity)
1292                         continue;
1293                 if (graph->edge[i].src == graph->edge[i].dst)
1294                         continue;
1295                 if (graph->edge[i].src->scc == graph->edge[i].dst->scc)
1296                         continue;
1297                 if (graph->edge[i].start > con)
1298                         continue;
1299                 if (graph->edge[i].end <= con)
1300                         continue;
1301                 graph->src_scc = graph->edge[i].src->scc;
1302                 graph->dst_scc = graph->edge[i].dst->scc;
1303         }
1304
1305         return 0;
1306 }
1307
1308 /* Check whether the next schedule row of the given node needs to be
1309  * non-trivial.  Lower-dimensional domains may have some trivial rows,
1310  * but as soon as the number of remaining required non-trivial rows
1311  * is as large as the number or remaining rows to be computed,
1312  * all remaining rows need to be non-trivial.
1313  */
1314 static int needs_row(struct isl_sched_graph *graph, struct isl_sched_node *node)
1315 {
1316         return node->nvar - node->rank >= graph->maxvar - graph->n_row;
1317 }
1318
1319 /* Solve the ILP problem constructed in setup_lp.
1320  * For each node such that all the remaining rows of its schedule
1321  * need to be non-trivial, we construct a non-triviality region.
1322  * This region imposes that the next row is independent of previous rows.
1323  * In particular the coefficients c_i_x are represented by t_i_x
1324  * variables with c_i_x = Q t_i_x and Q a unimodular matrix such that
1325  * its first columns span the rows of the previously computed part
1326  * of the schedule.  The non-triviality region enforces that at least
1327  * one of the remaining components of t_i_x is non-zero, i.e.,
1328  * that the new schedule row depends on at least one of the remaining
1329  * columns of Q.
1330  */
1331 static __isl_give isl_vec *solve_lp(struct isl_sched_graph *graph)
1332 {
1333         int i;
1334         isl_vec *sol;
1335         isl_basic_set *lp;
1336
1337         for (i = 0; i < graph->n; ++i) {
1338                 struct isl_sched_node *node = &graph->node[i];
1339                 int skip = node->rank;
1340                 graph->region[i].pos = node->start + 1 + 2*(node->nparam+skip);
1341                 if (needs_row(graph, node))
1342                         graph->region[i].len = 2 * (node->nvar - skip);
1343                 else
1344                         graph->region[i].len = 0;
1345         }
1346         lp = isl_basic_set_copy(graph->lp);
1347         sol = isl_tab_basic_set_non_trivial_lexmin(lp, 2, graph->n,
1348                                        graph->region, &check_conflict, graph);
1349         return sol;
1350 }
1351
1352 /* Update the schedules of all nodes based on the given solution
1353  * of the LP problem.
1354  * The new row is added to the current band.
1355  * All possibly negative coefficients are encoded as a difference
1356  * of two non-negative variables, so we need to perform the subtraction
1357  * here.  Moreover, if use_cmap is set, then the solution does
1358  * not refer to the actual coefficients c_i_x, but instead to variables
1359  * t_i_x such that c_i_x = Q t_i_x and Q is equal to node->cmap.
1360  * In this case, we then also need to perform this multiplication
1361  * to obtain the values of c_i_x.
1362  *
1363  * If check_zero is set, then the first two coordinates of sol are
1364  * assumed to correspond to the dependence distance.  If these two
1365  * coordinates are zero, then the corresponding scheduling dimension
1366  * is marked as being zero distance.
1367  */
1368 static int update_schedule(struct isl_sched_graph *graph,
1369         __isl_take isl_vec *sol, int use_cmap, int check_zero)
1370 {
1371         int i, j;
1372         int zero = 0;
1373         isl_vec *csol = NULL;
1374
1375         if (!sol)
1376                 goto error;
1377         if (sol->size == 0)
1378                 isl_die(sol->ctx, isl_error_internal,
1379                         "no solution found", goto error);
1380
1381         if (check_zero)
1382                 zero = isl_int_is_zero(sol->el[1]) &&
1383                            isl_int_is_zero(sol->el[2]);
1384
1385         for (i = 0; i < graph->n; ++i) {
1386                 struct isl_sched_node *node = &graph->node[i];
1387                 int pos = node->start;
1388                 int row = isl_mat_rows(node->sched);
1389
1390                 isl_vec_free(csol);
1391                 csol = isl_vec_alloc(sol->ctx, node->nvar);
1392                 if (!csol)
1393                         goto error;
1394
1395                 isl_map_free(node->sched_map);
1396                 node->sched_map = NULL;
1397                 node->sched = isl_mat_add_rows(node->sched, 1);
1398                 if (!node->sched)
1399                         goto error;
1400                 node->sched = isl_mat_set_element(node->sched, row, 0,
1401                                                   sol->el[1 + pos]);
1402                 for (j = 0; j < node->nparam + node->nvar; ++j)
1403                         isl_int_sub(sol->el[1 + pos + 1 + 2 * j + 1],
1404                                     sol->el[1 + pos + 1 + 2 * j + 1],
1405                                     sol->el[1 + pos + 1 + 2 * j]);
1406                 for (j = 0; j < node->nparam; ++j)
1407                         node->sched = isl_mat_set_element(node->sched,
1408                                         row, 1 + j, sol->el[1+pos+1+2*j+1]);
1409                 for (j = 0; j < node->nvar; ++j)
1410                         isl_int_set(csol->el[j],
1411                                     sol->el[1+pos+1+2*(node->nparam+j)+1]);
1412                 if (use_cmap)
1413                         csol = isl_mat_vec_product(isl_mat_copy(node->cmap),
1414                                                    csol);
1415                 if (!csol)
1416                         goto error;
1417                 for (j = 0; j < node->nvar; ++j)
1418                         node->sched = isl_mat_set_element(node->sched,
1419                                         row, 1 + node->nparam + j, csol->el[j]);
1420                 node->band[graph->n_total_row] = graph->n_band;
1421                 node->zero[graph->n_total_row] = zero;
1422         }
1423         isl_vec_free(sol);
1424         isl_vec_free(csol);
1425
1426         graph->n_row++;
1427         graph->n_total_row++;
1428
1429         return 0;
1430 error:
1431         isl_vec_free(sol);
1432         isl_vec_free(csol);
1433         return -1;
1434 }
1435
1436 /* Convert node->sched into a map and return this map.
1437  * We simply add equality constraints that express each output variable
1438  * as the affine combination of parameters and input variables specified
1439  * by the schedule matrix.
1440  *
1441  * The result is cached in node->sched_map, which needs to be released
1442  * whenever node->sched is updated.
1443  */
1444 static __isl_give isl_map *node_extract_schedule(struct isl_sched_node *node)
1445 {
1446         int i, j;
1447         isl_space *dim;
1448         isl_local_space *ls;
1449         isl_basic_map *bmap;
1450         isl_constraint *c;
1451         int nrow, ncol;
1452         isl_int v;
1453
1454         if (node->sched_map)
1455                 return isl_map_copy(node->sched_map);
1456
1457         nrow = isl_mat_rows(node->sched);
1458         ncol = isl_mat_cols(node->sched) - 1;
1459         dim = isl_space_from_domain(isl_space_copy(node->dim));
1460         dim = isl_space_add_dims(dim, isl_dim_out, nrow);
1461         bmap = isl_basic_map_universe(isl_space_copy(dim));
1462         ls = isl_local_space_from_space(dim);
1463
1464         isl_int_init(v);
1465
1466         for (i = 0; i < nrow; ++i) {
1467                 c = isl_equality_alloc(isl_local_space_copy(ls));
1468                 isl_constraint_set_coefficient_si(c, isl_dim_out, i, -1);
1469                 isl_mat_get_element(node->sched, i, 0, &v);
1470                 isl_constraint_set_constant(c, v);
1471                 for (j = 0; j < node->nparam; ++j) {
1472                         isl_mat_get_element(node->sched, i, 1 + j, &v);
1473                         isl_constraint_set_coefficient(c, isl_dim_param, j, v);
1474                 }
1475                 for (j = 0; j < node->nvar; ++j) {
1476                         isl_mat_get_element(node->sched,
1477                                             i, 1 + node->nparam + j, &v);
1478                         isl_constraint_set_coefficient(c, isl_dim_in, j, v);
1479                 }
1480                 bmap = isl_basic_map_add_constraint(bmap, c);
1481         }
1482
1483         isl_int_clear(v);
1484
1485         isl_local_space_free(ls);
1486
1487         node->sched_map = isl_map_from_basic_map(bmap);
1488         return isl_map_copy(node->sched_map);
1489 }
1490
1491 /* Update the given dependence relation based on the current schedule.
1492  * That is, intersect the dependence relation with a map expressing
1493  * that source and sink are executed within the same iteration of
1494  * the current schedule.
1495  * This is not the most efficient way, but this shouldn't be a critical
1496  * operation.
1497  */
1498 static __isl_give isl_map *specialize(__isl_take isl_map *map,
1499         struct isl_sched_node *src, struct isl_sched_node *dst)
1500 {
1501         isl_map *src_sched, *dst_sched, *id;
1502
1503         src_sched = node_extract_schedule(src);
1504         dst_sched = node_extract_schedule(dst);
1505         id = isl_map_apply_range(src_sched, isl_map_reverse(dst_sched));
1506         return isl_map_intersect(map, id);
1507 }
1508
1509 /* Update the dependence relations of all edges based on the current schedule.
1510  * If a dependence is carried completely by the current schedule, then
1511  * it is removed and edge_table is updated accordingly.
1512  */
1513 static int update_edges(isl_ctx *ctx, struct isl_sched_graph *graph)
1514 {
1515         int i;
1516         int reset_table = 0;
1517
1518         for (i = graph->n_edge - 1; i >= 0; --i) {
1519                 struct isl_sched_edge *edge = &graph->edge[i];
1520                 edge->map = specialize(edge->map, edge->src, edge->dst);
1521                 if (!edge->map)
1522                         return -1;
1523
1524                 if (isl_map_plain_is_empty(edge->map)) {
1525                         reset_table = 1;
1526                         isl_map_free(edge->map);
1527                         if (i != graph->n_edge - 1)
1528                                 graph->edge[i] = graph->edge[graph->n_edge - 1];
1529                         graph->n_edge--;
1530                 }
1531         }
1532
1533         if (reset_table) {
1534                 isl_hash_table_free(ctx, graph->edge_table);
1535                 graph->edge_table = NULL;
1536                 return graph_init_edge_table(ctx, graph);
1537         }
1538
1539         return 0;
1540 }
1541
1542 static void next_band(struct isl_sched_graph *graph)
1543 {
1544         graph->band_start = graph->n_total_row;
1545         graph->n_band++;
1546 }
1547
1548 /* Topologically sort statements mapped to same schedule iteration
1549  * and add a row to the schedule corresponding to this order.
1550  */
1551 static int sort_statements(isl_ctx *ctx, struct isl_sched_graph *graph)
1552 {
1553         int i, j;
1554
1555         if (graph->n <= 1)
1556                 return 0;
1557
1558         if (update_edges(ctx, graph) < 0)
1559                 return -1;
1560
1561         if (graph->n_edge == 0)
1562                 return 0;
1563
1564         if (detect_sccs(graph) < 0)
1565                 return -1;
1566
1567         for (i = 0; i < graph->n; ++i) {
1568                 struct isl_sched_node *node = &graph->node[i];
1569                 int row = isl_mat_rows(node->sched);
1570                 int cols = isl_mat_cols(node->sched);
1571
1572                 isl_map_free(node->sched_map);
1573                 node->sched_map = NULL;
1574                 node->sched = isl_mat_add_rows(node->sched, 1);
1575                 if (!node->sched)
1576                         return -1;
1577                 node->sched = isl_mat_set_element_si(node->sched, row, 0,
1578                                                      node->scc);
1579                 for (j = 1; j < cols; ++j)
1580                         node->sched = isl_mat_set_element_si(node->sched,
1581                                                              row, j, 0);
1582                 node->band[graph->n_total_row] = graph->n_band;
1583         }
1584
1585         graph->n_total_row++;
1586         next_band(graph);
1587
1588         return 0;
1589 }
1590
1591 /* Construct an isl_schedule based on the computed schedule stored
1592  * in graph and with parameters specified by dim.
1593  */
1594 static __isl_give isl_schedule *extract_schedule(struct isl_sched_graph *graph,
1595         __isl_take isl_space *dim)
1596 {
1597         int i;
1598         isl_ctx *ctx;
1599         isl_schedule *sched = NULL;
1600                 
1601         if (!dim)
1602                 return NULL;
1603
1604         ctx = isl_space_get_ctx(dim);
1605         sched = isl_calloc(ctx, struct isl_schedule,
1606                            sizeof(struct isl_schedule) +
1607                            (graph->n - 1) * sizeof(struct isl_schedule_node));
1608         if (!sched)
1609                 goto error;
1610
1611         sched->ref = 1;
1612         sched->n = graph->n;
1613         sched->n_band = graph->n_band;
1614         sched->n_total_row = graph->n_total_row;
1615
1616         for (i = 0; i < sched->n; ++i) {
1617                 int r, b;
1618                 int *band_end, *band_id, *zero;
1619
1620                 band_end = isl_alloc_array(ctx, int, graph->n_band);
1621                 band_id = isl_alloc_array(ctx, int, graph->n_band);
1622                 zero = isl_alloc_array(ctx, int, graph->n_total_row);
1623                 sched->node[i].sched = node_extract_schedule(&graph->node[i]);
1624                 sched->node[i].band_end = band_end;
1625                 sched->node[i].band_id = band_id;
1626                 sched->node[i].zero = zero;
1627                 if (!band_end || !band_id || !zero)
1628                         goto error;
1629
1630                 for (r = 0; r < graph->n_total_row; ++r)
1631                         zero[r] = graph->node[i].zero[r];
1632                 for (r = b = 0; r < graph->n_total_row; ++r) {
1633                         if (graph->node[i].band[r] == b)
1634                                 continue;
1635                         band_end[b++] = r;
1636                         if (graph->node[i].band[r] == -1)
1637                                 break;
1638                 }
1639                 if (r == graph->n_total_row)
1640                         band_end[b++] = r;
1641                 sched->node[i].n_band = b;
1642                 for (--b; b >= 0; --b)
1643                         band_id[b] = graph->node[i].band_id[b];
1644         }
1645
1646         sched->dim = dim;
1647
1648         return sched;
1649 error:
1650         isl_space_free(dim);
1651         isl_schedule_free(sched);
1652         return NULL;
1653 }
1654
1655 /* Copy nodes that satisfy node_pred from the src dependence graph
1656  * to the dst dependence graph.
1657  */
1658 static int copy_nodes(struct isl_sched_graph *dst, struct isl_sched_graph *src,
1659         int (*node_pred)(struct isl_sched_node *node, int data), int data)
1660 {
1661         int i;
1662
1663         dst->n = 0;
1664         for (i = 0; i < src->n; ++i) {
1665                 if (!node_pred(&src->node[i], data))
1666                         continue;
1667                 dst->node[dst->n].dim = isl_space_copy(src->node[i].dim);
1668                 dst->node[dst->n].nvar = src->node[i].nvar;
1669                 dst->node[dst->n].nparam = src->node[i].nparam;
1670                 dst->node[dst->n].sched = isl_mat_copy(src->node[i].sched);
1671                 dst->node[dst->n].sched_map =
1672                         isl_map_copy(src->node[i].sched_map);
1673                 dst->node[dst->n].band = src->node[i].band;
1674                 dst->node[dst->n].band_id = src->node[i].band_id;
1675                 dst->node[dst->n].zero = src->node[i].zero;
1676                 dst->n++;
1677         }
1678
1679         return 0;
1680 }
1681
1682 /* Copy non-empty edges that satisfy edge_pred from the src dependence graph
1683  * to the dst dependence graph.
1684  * If the source or destination node of the edge is not in the destination
1685  * graph, then it must be a backward proximity edge and it should simply
1686  * be ignored.
1687  */
1688 static int copy_edges(isl_ctx *ctx, struct isl_sched_graph *dst,
1689         struct isl_sched_graph *src,
1690         int (*edge_pred)(struct isl_sched_edge *edge, int data), int data)
1691 {
1692         int i;
1693
1694         dst->n_edge = 0;
1695         for (i = 0; i < src->n_edge; ++i) {
1696                 struct isl_sched_edge *edge = &src->edge[i];
1697                 isl_map *map;
1698                 struct isl_sched_node *dst_src, *dst_dst;
1699
1700                 if (!edge_pred(edge, data))
1701                         continue;
1702
1703                 if (isl_map_plain_is_empty(edge->map))
1704                         continue;
1705
1706                 dst_src = graph_find_node(ctx, dst, edge->src->dim);
1707                 dst_dst = graph_find_node(ctx, dst, edge->dst->dim);
1708                 if (!dst_src || !dst_dst) {
1709                         if (edge->validity)
1710                                 isl_die(ctx, isl_error_internal,
1711                                         "backward validity edge", return -1);
1712                         continue;
1713                 }
1714
1715                 map = isl_map_copy(edge->map);
1716
1717                 dst->edge[dst->n_edge].src = dst_src;
1718                 dst->edge[dst->n_edge].dst = dst_dst;
1719                 dst->edge[dst->n_edge].map = map;
1720                 dst->edge[dst->n_edge].validity = edge->validity;
1721                 dst->edge[dst->n_edge].proximity = edge->proximity;
1722                 dst->n_edge++;
1723         }
1724
1725         return 0;
1726 }
1727
1728 /* Given a "src" dependence graph that contains the nodes from "dst"
1729  * that satisfy node_pred, copy the schedule computed in "src"
1730  * for those nodes back to "dst".
1731  */
1732 static int copy_schedule(struct isl_sched_graph *dst,
1733         struct isl_sched_graph *src,
1734         int (*node_pred)(struct isl_sched_node *node, int data), int data)
1735 {
1736         int i;
1737
1738         src->n = 0;
1739         for (i = 0; i < dst->n; ++i) {
1740                 if (!node_pred(&dst->node[i], data))
1741                         continue;
1742                 isl_mat_free(dst->node[i].sched);
1743                 isl_map_free(dst->node[i].sched_map);
1744                 dst->node[i].sched = isl_mat_copy(src->node[src->n].sched);
1745                 dst->node[i].sched_map =
1746                         isl_map_copy(src->node[src->n].sched_map);
1747                 src->n++;
1748         }
1749
1750         dst->n_total_row = src->n_total_row;
1751         dst->n_band = src->n_band;
1752
1753         return 0;
1754 }
1755
1756 /* Compute the maximal number of variables over all nodes.
1757  * This is the maximal number of linearly independent schedule
1758  * rows that we need to compute.
1759  * Just in case we end up in a part of the dependence graph
1760  * with only lower-dimensional domains, we make sure we will
1761  * compute the required amount of extra linearly independent rows.
1762  */
1763 static int compute_maxvar(struct isl_sched_graph *graph)
1764 {
1765         int i;
1766
1767         graph->maxvar = 0;
1768         for (i = 0; i < graph->n; ++i) {
1769                 struct isl_sched_node *node = &graph->node[i];
1770                 int nvar;
1771
1772                 if (node_update_cmap(node) < 0)
1773                         return -1;
1774                 nvar = node->nvar + graph->n_row - node->rank;
1775                 if (nvar > graph->maxvar)
1776                         graph->maxvar = nvar;
1777         }
1778
1779         return 0;
1780 }
1781
1782 static int compute_schedule(isl_ctx *ctx, struct isl_sched_graph *graph);
1783 static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph);
1784
1785 /* Compute a schedule for a subgraph of "graph".  In particular, for
1786  * the graph composed of nodes that satisfy node_pred and edges that
1787  * that satisfy edge_pred.  The caller should precompute the number
1788  * of nodes and edges that satisfy these predicates and pass them along
1789  * as "n" and "n_edge".
1790  * If the subgraph is known to consist of a single component, then wcc should
1791  * be set and then we call compute_schedule_wcc on the constructed subgraph.
1792  * Otherwise, we call compute_schedule, which will check whether the subgraph
1793  * is connected.
1794  */
1795 static int compute_sub_schedule(isl_ctx *ctx,
1796         struct isl_sched_graph *graph, int n, int n_edge,
1797         int (*node_pred)(struct isl_sched_node *node, int data),
1798         int (*edge_pred)(struct isl_sched_edge *edge, int data),
1799         int data, int wcc)
1800 {
1801         struct isl_sched_graph split = { 0 };
1802
1803         if (graph_alloc(ctx, &split, n, n_edge) < 0)
1804                 goto error;
1805         if (copy_nodes(&split, graph, node_pred, data) < 0)
1806                 goto error;
1807         if (graph_init_table(ctx, &split) < 0)
1808                 goto error;
1809         if (copy_edges(ctx, &split, graph, edge_pred, data) < 0)
1810                 goto error;
1811         if (graph_init_edge_table(ctx, &split) < 0)
1812                 goto error;
1813         split.n_row = graph->n_row;
1814         split.n_total_row = graph->n_total_row;
1815         split.n_band = graph->n_band;
1816         split.band_start = graph->band_start;
1817
1818         if (wcc && compute_schedule_wcc(ctx, &split) < 0)
1819                 goto error;
1820         if (!wcc && compute_schedule(ctx, &split) < 0)
1821                 goto error;
1822
1823         copy_schedule(graph, &split, node_pred, data);
1824
1825         graph_free(ctx, &split);
1826         return 0;
1827 error:
1828         graph_free(ctx, &split);
1829         return -1;
1830 }
1831
1832 static int node_scc_exactly(struct isl_sched_node *node, int scc)
1833 {
1834         return node->scc == scc;
1835 }
1836
1837 static int node_scc_at_most(struct isl_sched_node *node, int scc)
1838 {
1839         return node->scc <= scc;
1840 }
1841
1842 static int node_scc_at_least(struct isl_sched_node *node, int scc)
1843 {
1844         return node->scc >= scc;
1845 }
1846
1847 static int edge_src_scc_exactly(struct isl_sched_edge *edge, int scc)
1848 {
1849         return edge->src->scc == scc;
1850 }
1851
1852 static int edge_dst_scc_at_most(struct isl_sched_edge *edge, int scc)
1853 {
1854         return edge->dst->scc <= scc;
1855 }
1856
1857 static int edge_src_scc_at_least(struct isl_sched_edge *edge, int scc)
1858 {
1859         return edge->src->scc >= scc;
1860 }
1861
1862 /* Pad the schedules of all nodes with zero rows such that in the end
1863  * they all have graph->n_total_row rows.
1864  * The extra rows don't belong to any band, so they get assigned band number -1.
1865  */
1866 static int pad_schedule(struct isl_sched_graph *graph)
1867 {
1868         int i, j;
1869
1870         for (i = 0; i < graph->n; ++i) {
1871                 struct isl_sched_node *node = &graph->node[i];
1872                 int row = isl_mat_rows(node->sched);
1873                 if (graph->n_total_row > row) {
1874                         isl_map_free(node->sched_map);
1875                         node->sched_map = NULL;
1876                 }
1877                 node->sched = isl_mat_add_zero_rows(node->sched,
1878                                                     graph->n_total_row - row);
1879                 if (!node->sched)
1880                         return -1;
1881                 for (j = row; j < graph->n_total_row; ++j)
1882                         node->band[j] = -1;
1883         }
1884
1885         return 0;
1886 }
1887
1888 /* Split the current graph into two parts and compute a schedule for each
1889  * part individually.  In particular, one part consists of all SCCs up
1890  * to and including graph->src_scc, while the other part contains the other
1891  * SCCS.
1892  *
1893  * The split is enforced in the schedule by constant rows with two different
1894  * values (0 and 1).  These constant rows replace the previously computed rows
1895  * in the current band.
1896  * It would be possible to reuse them as the first rows in the next
1897  * band, but recomputing them may result in better rows as we are looking
1898  * at a smaller part of the dependence graph.
1899  * compute_split_schedule is only called when no zero-distance schedule row
1900  * could be found on the entire graph, so we wark the splitting row as
1901  * non zero-distance.
1902  *
1903  * The band_id of the second group is set to n, where n is the number
1904  * of nodes in the first group.  This ensures that the band_ids over
1905  * the two groups remain disjoint, even if either or both of the two
1906  * groups contain independent components.
1907  */
1908 static int compute_split_schedule(isl_ctx *ctx, struct isl_sched_graph *graph)
1909 {
1910         int i, j, n, e1, e2;
1911         int n_total_row, orig_total_row;
1912         int n_band, orig_band;
1913         int drop;
1914
1915         drop = graph->n_total_row - graph->band_start;
1916         graph->n_total_row -= drop;
1917         graph->n_row -= drop;
1918
1919         n = 0;
1920         for (i = 0; i < graph->n; ++i) {
1921                 struct isl_sched_node *node = &graph->node[i];
1922                 int row = isl_mat_rows(node->sched) - drop;
1923                 int cols = isl_mat_cols(node->sched);
1924                 int before = node->scc <= graph->src_scc;
1925
1926                 if (before)
1927                         n++;
1928
1929                 isl_map_free(node->sched_map);
1930                 node->sched_map = NULL;
1931                 node->sched = isl_mat_drop_rows(node->sched,
1932                                                 graph->band_start, drop);
1933                 node->sched = isl_mat_add_rows(node->sched, 1);
1934                 if (!node->sched)
1935                         return -1;
1936                 node->sched = isl_mat_set_element_si(node->sched, row, 0,
1937                                                      !before);
1938                 for (j = 1; j < cols; ++j)
1939                         node->sched = isl_mat_set_element_si(node->sched,
1940                                                              row, j, 0);
1941                 node->band[graph->n_total_row] = graph->n_band;
1942                 node->zero[graph->n_total_row] = 0;
1943         }
1944
1945         e1 = e2 = 0;
1946         for (i = 0; i < graph->n_edge; ++i) {
1947                 if (graph->edge[i].dst->scc <= graph->src_scc)
1948                         e1++;
1949                 if (graph->edge[i].src->scc > graph->src_scc)
1950                         e2++;
1951         }
1952
1953         graph->n_total_row++;
1954         next_band(graph);
1955
1956         for (i = 0; i < graph->n; ++i) {
1957                 struct isl_sched_node *node = &graph->node[i];
1958                 if (node->scc > graph->src_scc)
1959                         node->band_id[graph->n_band] = n;
1960         }
1961
1962         orig_total_row = graph->n_total_row;
1963         orig_band = graph->n_band;
1964         if (compute_sub_schedule(ctx, graph, n, e1,
1965                                 &node_scc_at_most, &edge_dst_scc_at_most,
1966                                 graph->src_scc, 0) < 0)
1967                 return -1;
1968         n_total_row = graph->n_total_row;
1969         graph->n_total_row = orig_total_row;
1970         n_band = graph->n_band;
1971         graph->n_band = orig_band;
1972         if (compute_sub_schedule(ctx, graph, graph->n - n, e2,
1973                                 &node_scc_at_least, &edge_src_scc_at_least,
1974                                 graph->src_scc + 1, 0) < 0)
1975                 return -1;
1976         if (n_total_row > graph->n_total_row)
1977                 graph->n_total_row = n_total_row;
1978         if (n_band > graph->n_band)
1979                 graph->n_band = n_band;
1980
1981         return pad_schedule(graph);
1982 }
1983
1984 /* Compute the next band of the schedule after updating the dependence
1985  * relations based on the the current schedule.
1986  */
1987 static int compute_next_band(isl_ctx *ctx, struct isl_sched_graph *graph)
1988 {
1989         if (update_edges(ctx, graph) < 0)
1990                 return -1;
1991         next_band(graph);
1992                 
1993         return compute_schedule(ctx, graph);
1994 }
1995
1996 /* Add constraints to graph->lp that force the dependence "map" (which
1997  * is part of the dependence relation of "edge")
1998  * to be respected and attempt to carry it, where the edge is one from
1999  * a node j to itself.  "pos" is the sequence number of the given map.
2000  * That is, add constraints that enforce
2001  *
2002  *      (c_j_0 + c_j_n n + c_j_x y) - (c_j_0 + c_j_n n + c_j_x x)
2003  *      = c_j_x (y - x) >= e_i
2004  *
2005  * for each (x,y) in R.
2006  * We obtain general constraints on coefficients (c_0, c_n, c_x)
2007  * of valid constraints for (y - x) and then plug in (-e_i, 0, c_j_x),
2008  * with each coefficient in c_j_x represented as a pair of non-negative
2009  * coefficients.
2010  */
2011 static int add_intra_constraints(struct isl_sched_graph *graph,
2012         struct isl_sched_edge *edge, __isl_take isl_map *map, int pos)
2013 {
2014         unsigned total;
2015         isl_ctx *ctx = isl_map_get_ctx(map);
2016         isl_space *dim;
2017         isl_dim_map *dim_map;
2018         isl_basic_set *coef;
2019         struct isl_sched_node *node = edge->src;
2020
2021         coef = intra_coefficients(graph, map);
2022
2023         dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
2024
2025         total = isl_basic_set_total_dim(graph->lp);
2026         dim_map = isl_dim_map_alloc(ctx, total);
2027         isl_dim_map_range(dim_map, 3 + pos, 0, 0, 0, 1, -1);
2028         isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
2029                           isl_space_dim(dim, isl_dim_set), 1,
2030                           node->nvar, -1);
2031         isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
2032                           isl_space_dim(dim, isl_dim_set), 1,
2033                           node->nvar, 1);
2034         graph->lp = isl_basic_set_extend_constraints(graph->lp,
2035                         coef->n_eq, coef->n_ineq);
2036         graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
2037                                                            coef, dim_map);
2038         isl_space_free(dim);
2039
2040         return 0;
2041 }
2042
2043 /* Add constraints to graph->lp that force the dependence "map" (which
2044  * is part of the dependence relation of "edge")
2045  * to be respected and attempt to carry it, where the edge is one from
2046  * node j to node k.  "pos" is the sequence number of the given map.
2047  * That is, add constraints that enforce
2048  *
2049  *      (c_k_0 + c_k_n n + c_k_x y) - (c_j_0 + c_j_n n + c_j_x x) >= e_i
2050  *
2051  * for each (x,y) in R.
2052  * We obtain general constraints on coefficients (c_0, c_n, c_x)
2053  * of valid constraints for R and then plug in
2054  * (-e_i + c_k_0 - c_j_0, c_k_n - c_j_n, c_k_x - c_j_x)
2055  * with each coefficient (except e_i, c_k_0 and c_j_0)
2056  * represented as a pair of non-negative coefficients.
2057  */
2058 static int add_inter_constraints(struct isl_sched_graph *graph,
2059         struct isl_sched_edge *edge, __isl_take isl_map *map, int pos)
2060 {
2061         unsigned total;
2062         isl_ctx *ctx = isl_map_get_ctx(map);
2063         isl_space *dim;
2064         isl_dim_map *dim_map;
2065         isl_basic_set *coef;
2066         struct isl_sched_node *src = edge->src;
2067         struct isl_sched_node *dst = edge->dst;
2068
2069         coef = inter_coefficients(graph, map);
2070
2071         dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
2072
2073         total = isl_basic_set_total_dim(graph->lp);
2074         dim_map = isl_dim_map_alloc(ctx, total);
2075
2076         isl_dim_map_range(dim_map, 3 + pos, 0, 0, 0, 1, -1);
2077
2078         isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, 1);
2079         isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, -1);
2080         isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, 1);
2081         isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
2082                           isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
2083                           dst->nvar, -1);
2084         isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
2085                           isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
2086                           dst->nvar, 1);
2087
2088         isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, -1);
2089         isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, 1);
2090         isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, -1);
2091         isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
2092                           isl_space_dim(dim, isl_dim_set), 1,
2093                           src->nvar, 1);
2094         isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
2095                           isl_space_dim(dim, isl_dim_set), 1,
2096                           src->nvar, -1);
2097
2098         graph->lp = isl_basic_set_extend_constraints(graph->lp,
2099                         coef->n_eq, coef->n_ineq);
2100         graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
2101                                                            coef, dim_map);
2102         isl_space_free(dim);
2103
2104         return 0;
2105 }
2106
2107 /* Add constraints to graph->lp that force all dependence
2108  * to be respected and attempt to carry it.
2109  */
2110 static int add_all_constraints(struct isl_sched_graph *graph)
2111 {
2112         int i, j;
2113         int pos;
2114
2115         pos = 0;
2116         for (i = 0; i < graph->n_edge; ++i) {
2117                 struct isl_sched_edge *edge= &graph->edge[i];
2118                 for (j = 0; j < edge->map->n; ++j) {
2119                         isl_basic_map *bmap;
2120                         isl_map *map;
2121
2122                         bmap = isl_basic_map_copy(edge->map->p[j]);
2123                         map = isl_map_from_basic_map(bmap);
2124
2125                         if (edge->src == edge->dst &&
2126                             add_intra_constraints(graph, edge, map, pos) < 0)
2127                                 return -1;
2128                         if (edge->src != edge->dst &&
2129                             add_inter_constraints(graph, edge, map, pos) < 0)
2130                                 return -1;
2131                         ++pos;
2132                 }
2133         }
2134
2135         return 0;
2136 }
2137
2138 /* Count the number of equality and inequality constraints
2139  * that will be added to the carry_lp problem.
2140  * If once is set, then we count
2141  * each edge exactly once.  Otherwise, we count as follows
2142  * validity             -> 1 (>= 0)
2143  * validity+proximity   -> 2 (>= 0 and upper bound)
2144  * proximity            -> 2 (lower and upper bound)
2145  */
2146 static int count_all_constraints(struct isl_sched_graph *graph,
2147         int *n_eq, int *n_ineq, int once)
2148 {
2149         int i, j;
2150
2151         *n_eq = *n_ineq = 0;
2152         for (i = 0; i < graph->n_edge; ++i) {
2153                 struct isl_sched_edge *edge= &graph->edge[i];
2154                 for (j = 0; j < edge->map->n; ++j) {
2155                         isl_basic_map *bmap;
2156                         isl_map *map;
2157
2158                         bmap = isl_basic_map_copy(edge->map->p[j]);
2159                         map = isl_map_from_basic_map(bmap);
2160
2161                         if (count_map_constraints(graph, edge, map,
2162                                                   n_eq, n_ineq, once) < 0)
2163                                     return -1;
2164                 }
2165         }
2166
2167         return 0;
2168 }
2169
2170 /* Construct an LP problem for finding schedule coefficients
2171  * such that the schedule carries as many dependences as possible.
2172  * In particular, for each dependence i, we bound the dependence distance
2173  * from below by e_i, with 0 <= e_i <= 1 and then maximize the sum
2174  * of all e_i's.  Dependence with e_i = 0 in the solution are simply
2175  * respected, while those with e_i > 0 (in practice e_i = 1) are carried.
2176  * Note that if the dependence relation is a union of basic maps,
2177  * then we have to consider each basic map individually as it may only
2178  * be possible to carry the dependences expressed by some of those
2179  * basic maps and not all off them.
2180  * Below, we consider each of those basic maps as a separate "edge".
2181  *
2182  * All variables of the LP are non-negative.  The actual coefficients
2183  * may be negative, so each coefficient is represented as the difference
2184  * of two non-negative variables.  The negative part always appears
2185  * immediately before the positive part.
2186  * Other than that, the variables have the following order
2187  *
2188  *      - sum of (1 - e_i) over all edges
2189  *      - sum of positive and negative parts of all c_n coefficients
2190  *              (unconstrained when computing non-parametric schedules)
2191  *      - sum of positive and negative parts of all c_x coefficients
2192  *      - for each edge
2193  *              - e_i
2194  *      - for each node
2195  *              - c_i_0
2196  *              - positive and negative parts of c_i_n (if parametric)
2197  *              - positive and negative parts of c_i_x
2198  *
2199  * The constraints are those from the edges plus three equalities
2200  * to express the sums and n_edge inequalities to express e_i <= 1.
2201  */
2202 static int setup_carry_lp(isl_ctx *ctx, struct isl_sched_graph *graph)
2203 {
2204         int i, j;
2205         int k;
2206         isl_space *dim;
2207         unsigned total;
2208         int n_eq, n_ineq;
2209         int n_edge;
2210
2211         n_edge = 0;
2212         for (i = 0; i < graph->n_edge; ++i)
2213                 n_edge += graph->edge[i].map->n;
2214
2215         total = 3 + n_edge;
2216         for (i = 0; i < graph->n; ++i) {
2217                 struct isl_sched_node *node = &graph->node[graph->sorted[i]];
2218                 node->start = total;
2219                 total += 1 + 2 * (node->nparam + node->nvar);
2220         }
2221
2222         if (count_all_constraints(graph, &n_eq, &n_ineq, 1) < 0)
2223                 return -1;
2224
2225         dim = isl_space_set_alloc(ctx, 0, total);
2226         isl_basic_set_free(graph->lp);
2227         n_eq += 3;
2228         n_ineq += n_edge;
2229         graph->lp = isl_basic_set_alloc_space(dim, 0, n_eq, n_ineq);
2230         graph->lp = isl_basic_set_set_rational(graph->lp);
2231
2232         k = isl_basic_set_alloc_equality(graph->lp);
2233         if (k < 0)
2234                 return -1;
2235         isl_seq_clr(graph->lp->eq[k], 1 +  total);
2236         isl_int_set_si(graph->lp->eq[k][0], -n_edge);
2237         isl_int_set_si(graph->lp->eq[k][1], 1);
2238         for (i = 0; i < n_edge; ++i)
2239                 isl_int_set_si(graph->lp->eq[k][4 + i], 1);
2240
2241         k = isl_basic_set_alloc_equality(graph->lp);
2242         if (k < 0)
2243                 return -1;
2244         isl_seq_clr(graph->lp->eq[k], 1 +  total);
2245         isl_int_set_si(graph->lp->eq[k][2], -1);
2246         for (i = 0; i < graph->n; ++i) {
2247                 int pos = 1 + graph->node[i].start + 1;
2248
2249                 for (j = 0; j < 2 * graph->node[i].nparam; ++j)
2250                         isl_int_set_si(graph->lp->eq[k][pos + j], 1);
2251         }
2252
2253         k = isl_basic_set_alloc_equality(graph->lp);
2254         if (k < 0)
2255                 return -1;
2256         isl_seq_clr(graph->lp->eq[k], 1 +  total);
2257         isl_int_set_si(graph->lp->eq[k][3], -1);
2258         for (i = 0; i < graph->n; ++i) {
2259                 struct isl_sched_node *node = &graph->node[i];
2260                 int pos = 1 + node->start + 1 + 2 * node->nparam;
2261
2262                 for (j = 0; j < 2 * node->nvar; ++j)
2263                         isl_int_set_si(graph->lp->eq[k][pos + j], 1);
2264         }
2265
2266         for (i = 0; i < n_edge; ++i) {
2267                 k = isl_basic_set_alloc_inequality(graph->lp);
2268                 if (k < 0)
2269                         return -1;
2270                 isl_seq_clr(graph->lp->ineq[k], 1 +  total);
2271                 isl_int_set_si(graph->lp->ineq[k][4 + i], -1);
2272                 isl_int_set_si(graph->lp->ineq[k][0], 1);
2273         }
2274
2275         if (add_all_constraints(graph) < 0)
2276                 return -1;
2277
2278         return 0;
2279 }
2280
2281 /* If the schedule_split_parallel option is set and if the linear
2282  * parts of the scheduling rows for all nodes in the graphs are the same,
2283  * then split off the constant term from the linear part.
2284  * The constant term is then placed in a separate band and
2285  * the linear part is simplified.
2286  */
2287 static int split_parallel(isl_ctx *ctx, struct isl_sched_graph *graph)
2288 {
2289         int i;
2290         int equal = 1;
2291         int row, cols;
2292         struct isl_sched_node *node0;
2293
2294         if (!ctx->opt->schedule_split_parallel)
2295                 return 0;
2296         if (graph->n <= 1)
2297                 return 0;
2298
2299         node0 = &graph->node[0];
2300         row = isl_mat_rows(node0->sched) - 1;
2301         cols = isl_mat_cols(node0->sched);
2302         for (i = 1; i < graph->n; ++i) {
2303                 struct isl_sched_node *node = &graph->node[i];
2304
2305                 if (isl_mat_cols(node->sched) != cols)
2306                         return 0;
2307                 if (!isl_seq_eq(node0->sched->row[row] + 1,
2308                                 node->sched->row[row] + 1, cols - 1))
2309                         return 0;
2310                 if (equal &&
2311                     isl_int_ne(node0->sched->row[row][0],
2312                                node->sched->row[row][0]))
2313                         equal = 0;
2314         }
2315         if (equal)
2316                 return 0;
2317
2318         next_band(graph);
2319
2320         for (i = 0; i < graph->n; ++i) {
2321                 struct isl_sched_node *node = &graph->node[i];
2322
2323                 isl_map_free(node->sched_map);
2324                 node->sched_map = NULL;
2325                 node->sched = isl_mat_add_zero_rows(node->sched, 1);
2326                 if (!node->sched)
2327                         return -1;
2328                 isl_int_set(node->sched->row[row + 1][0],
2329                             node->sched->row[row][0]);
2330                 isl_int_set_si(node->sched->row[row][0], 0);
2331                 node->sched = isl_mat_normalize_row(node->sched, row);
2332                 if (!node->sched)
2333                         return -1;
2334                 node->band[graph->n_total_row] = graph->n_band;
2335         }
2336
2337         graph->n_total_row++;
2338
2339         return 0;
2340 }
2341
2342 /* Construct a schedule row for each node such that as many dependences
2343  * as possible are carried and then continue with the next band.
2344  */
2345 static int carry_dependences(isl_ctx *ctx, struct isl_sched_graph *graph)
2346 {
2347         int i;
2348         int n_edge;
2349         isl_vec *sol;
2350         isl_basic_set *lp;
2351
2352         n_edge = 0;
2353         for (i = 0; i < graph->n_edge; ++i)
2354                 n_edge += graph->edge[i].map->n;
2355
2356         if (setup_carry_lp(ctx, graph) < 0)
2357                 return -1;
2358
2359         lp = isl_basic_set_copy(graph->lp);
2360         sol = isl_tab_basic_set_non_neg_lexmin(lp);
2361         if (!sol)
2362                 return -1;
2363
2364         if (sol->size == 0) {
2365                 isl_vec_free(sol);
2366                 isl_die(ctx, isl_error_internal,
2367                         "error in schedule construction", return -1);
2368         }
2369
2370         if (isl_int_cmp_si(sol->el[1], n_edge) >= 0) {
2371                 isl_vec_free(sol);
2372                 isl_die(ctx, isl_error_unknown,
2373                         "unable to carry dependences", return -1);
2374         }
2375
2376         if (update_schedule(graph, sol, 0, 0) < 0)
2377                 return -1;
2378
2379         if (split_parallel(ctx, graph) < 0)
2380                 return -1;
2381
2382         return compute_next_band(ctx, graph);
2383 }
2384
2385 /* Are there any validity edges in the graph?
2386  */
2387 static int has_validity_edges(struct isl_sched_graph *graph)
2388 {
2389         int i;
2390
2391         for (i = 0; i < graph->n_edge; ++i)
2392                 if (graph->edge[i].validity)
2393                         return 1;
2394
2395         return 0;
2396 }
2397
2398 /* Should we apply a Feautrier step?
2399  * That is, did the user request the Feautrier algorithm and are
2400  * there any validity dependences (left)?
2401  */
2402 static int need_feautrier_step(isl_ctx *ctx, struct isl_sched_graph *graph)
2403 {
2404         if (ctx->opt->schedule_algorithm != ISL_SCHEDULE_ALGORITHM_FEAUTRIER)
2405                 return 0;
2406
2407         return has_validity_edges(graph);
2408 }
2409
2410 /* Compute a schedule for a connected dependence graph using Feautrier's
2411  * multi-dimensional scheduling algorithm.
2412  * The original algorithm is described in [1].
2413  * The main idea is to minimize the number of scheduling dimensions, by
2414  * trying to satisfy as many dependences as possible per scheduling dimension.
2415  *
2416  * [1] P. Feautrier, Some Efficient Solutions to the Affine Scheduling
2417  *     Problem, Part II: Multi-Dimensional Time.
2418  *     In Intl. Journal of Parallel Programming, 1992.
2419  */
2420 static int compute_schedule_wcc_feautrier(isl_ctx *ctx,
2421         struct isl_sched_graph *graph)
2422 {
2423         return carry_dependences(ctx, graph);
2424 }
2425
2426 /* Compute a schedule for a connected dependence graph.
2427  * We try to find a sequence of as many schedule rows as possible that result
2428  * in non-negative dependence distances (independent of the previous rows
2429  * in the sequence, i.e., such that the sequence is tilable).
2430  * If we can't find any more rows we either
2431  * - split between SCCs and start over (assuming we found an interesting
2432  *      pair of SCCs between which to split)
2433  * - continue with the next band (assuming the current band has at least
2434  *      one row)
2435  * - try to carry as many dependences as possible and continue with the next
2436  *      band
2437  *
2438  * If Feautrier's algorithm is selected, we first recursively try to satisfy
2439  * as many validity dependences as possible. When all validity dependences
2440  * are satisfied we extend the schedule to a full-dimensional schedule.
2441  *
2442  * If we manage to complete the schedule, we finish off by topologically
2443  * sorting the statements based on the remaining dependences.
2444  *
2445  * If ctx->opt->schedule_outer_zero_distance is set, then we force the
2446  * outermost dimension in the current band to be zero distance.  If this
2447  * turns out to be impossible, we fall back on the general scheme above
2448  * and try to carry as many dependences as possible.
2449  */
2450 static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph)
2451 {
2452         int force_zero = 0;
2453
2454         if (detect_sccs(graph) < 0)
2455                 return -1;
2456         sort_sccs(graph);
2457
2458         if (compute_maxvar(graph) < 0)
2459                 return -1;
2460
2461         if (need_feautrier_step(ctx, graph))
2462                 return compute_schedule_wcc_feautrier(ctx, graph);
2463
2464         if (ctx->opt->schedule_outer_zero_distance)
2465                 force_zero = 1;
2466
2467         while (graph->n_row < graph->maxvar) {
2468                 isl_vec *sol;
2469
2470                 graph->src_scc = -1;
2471                 graph->dst_scc = -1;
2472
2473                 if (setup_lp(ctx, graph, force_zero) < 0)
2474                         return -1;
2475                 sol = solve_lp(graph);
2476                 if (!sol)
2477                         return -1;
2478                 if (sol->size == 0) {
2479                         isl_vec_free(sol);
2480                         if (!ctx->opt->schedule_maximize_band_depth &&
2481                             graph->n_total_row > graph->band_start)
2482                                 return compute_next_band(ctx, graph);
2483                         if (graph->src_scc >= 0)
2484                                 return compute_split_schedule(ctx, graph);
2485                         if (graph->n_total_row > graph->band_start)
2486                                 return compute_next_band(ctx, graph);
2487                         return carry_dependences(ctx, graph);
2488                 }
2489                 if (update_schedule(graph, sol, 1, 1) < 0)
2490                         return -1;
2491                 force_zero = 0;
2492         }
2493
2494         if (graph->n_total_row > graph->band_start)
2495                 next_band(graph);
2496         return sort_statements(ctx, graph);
2497 }
2498
2499 /* Compute a schedule for each component (identified by node->scc)
2500  * of the dependence graph separately and then combine the results.
2501  *
2502  * The band_id is adjusted such that each component has a separate id.
2503  * Note that the band_id may have already been set to a value different
2504  * from zero by compute_split_schedule.
2505  */
2506 static int compute_component_schedule(isl_ctx *ctx,
2507         struct isl_sched_graph *graph)
2508 {
2509         int wcc, i;
2510         int n, n_edge;
2511         int n_total_row, orig_total_row;
2512         int n_band, orig_band;
2513
2514         n_total_row = 0;
2515         orig_total_row = graph->n_total_row;
2516         n_band = 0;
2517         orig_band = graph->n_band;
2518         for (i = 0; i < graph->n; ++i)
2519                 graph->node[i].band_id[graph->n_band] += graph->node[i].scc;
2520         for (wcc = 0; wcc < graph->scc; ++wcc) {
2521                 n = 0;
2522                 for (i = 0; i < graph->n; ++i)
2523                         if (graph->node[i].scc == wcc)
2524                                 n++;
2525                 n_edge = 0;
2526                 for (i = 0; i < graph->n_edge; ++i)
2527                         if (graph->edge[i].src->scc == wcc)
2528                                 n_edge++;
2529
2530                 if (compute_sub_schedule(ctx, graph, n, n_edge,
2531                                     &node_scc_exactly,
2532                                     &edge_src_scc_exactly, wcc, 1) < 0)
2533                         return -1;
2534                 if (graph->n_total_row > n_total_row)
2535                         n_total_row = graph->n_total_row;
2536                 graph->n_total_row = orig_total_row;
2537                 if (graph->n_band > n_band)
2538                         n_band = graph->n_band;
2539                 graph->n_band = orig_band;
2540         }
2541
2542         graph->n_total_row = n_total_row;
2543         graph->n_band = n_band;
2544
2545         return pad_schedule(graph);
2546 }
2547
2548 /* Compute a schedule for the given dependence graph.
2549  * We first check if the graph is connected (through validity dependences)
2550  * and, if not, compute a schedule for each component separately.
2551  */
2552 static int compute_schedule(isl_ctx *ctx, struct isl_sched_graph *graph)
2553 {
2554         if (detect_wccs(graph) < 0)
2555                 return -1;
2556
2557         if (graph->scc > 1)
2558                 return compute_component_schedule(ctx, graph);
2559
2560         return compute_schedule_wcc(ctx, graph);
2561 }
2562
2563 /* Compute a schedule for the given union of domains that respects
2564  * all the validity dependences.
2565  * If the default isl scheduling algorithm is used, it tries to minimize
2566  * the dependence distances over the proximity dependences.
2567  * If Feautrier's scheduling algorithm is used, the proximity dependence
2568  * distances are only minimized during the extension to a full-dimensional
2569  * schedule.
2570  */
2571 __isl_give isl_schedule *isl_union_set_compute_schedule(
2572         __isl_take isl_union_set *domain,
2573         __isl_take isl_union_map *validity,
2574         __isl_take isl_union_map *proximity)
2575 {
2576         isl_ctx *ctx = isl_union_set_get_ctx(domain);
2577         isl_space *dim;
2578         struct isl_sched_graph graph = { 0 };
2579         isl_schedule *sched;
2580
2581         domain = isl_union_set_align_params(domain,
2582                                             isl_union_map_get_space(validity));
2583         domain = isl_union_set_align_params(domain,
2584                                             isl_union_map_get_space(proximity));
2585         dim = isl_union_set_get_space(domain);
2586         validity = isl_union_map_align_params(validity, isl_space_copy(dim));
2587         proximity = isl_union_map_align_params(proximity, dim);
2588
2589         if (!domain)
2590                 goto error;
2591
2592         graph.n = isl_union_set_n_set(domain);
2593         if (graph.n == 0)
2594                 goto empty;
2595         if (graph_alloc(ctx, &graph, graph.n,
2596             isl_union_map_n_map(validity) + isl_union_map_n_map(proximity)) < 0)
2597                 goto error;
2598         if (compute_max_row(&graph, domain) < 0)
2599                 goto error;
2600         graph.root = 1;
2601         graph.n = 0;
2602         if (isl_union_set_foreach_set(domain, &extract_node, &graph) < 0)
2603                 goto error;
2604         if (graph_init_table(ctx, &graph) < 0)
2605                 goto error;
2606         graph.n_edge = 0;
2607         if (isl_union_map_foreach_map(validity, &extract_edge, &graph) < 0)
2608                 goto error;
2609         if (graph_init_edge_table(ctx, &graph) < 0)
2610                 goto error;
2611         if (isl_union_map_foreach_map(proximity, &extract_edge, &graph) < 0)
2612                 goto error;
2613
2614         if (compute_schedule(ctx, &graph) < 0)
2615                 goto error;
2616
2617 empty:
2618         sched = extract_schedule(&graph, isl_union_set_get_space(domain));
2619
2620         graph_free(ctx, &graph);
2621         isl_union_set_free(domain);
2622         isl_union_map_free(validity);
2623         isl_union_map_free(proximity);
2624
2625         return sched;
2626 error:
2627         graph_free(ctx, &graph);
2628         isl_union_set_free(domain);
2629         isl_union_map_free(validity);
2630         isl_union_map_free(proximity);
2631         return NULL;
2632 }
2633
2634 void *isl_schedule_free(__isl_take isl_schedule *sched)
2635 {
2636         int i;
2637         if (!sched)
2638                 return NULL;
2639
2640         if (--sched->ref > 0)
2641                 return NULL;
2642
2643         for (i = 0; i < sched->n; ++i) {
2644                 isl_map_free(sched->node[i].sched);
2645                 free(sched->node[i].band_end);
2646                 free(sched->node[i].band_id);
2647                 free(sched->node[i].zero);
2648         }
2649         isl_space_free(sched->dim);
2650         isl_band_list_free(sched->band_forest);
2651         free(sched);
2652         return NULL;
2653 }
2654
2655 isl_ctx *isl_schedule_get_ctx(__isl_keep isl_schedule *schedule)
2656 {
2657         return schedule ? isl_space_get_ctx(schedule->dim) : NULL;
2658 }
2659
2660 __isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched)
2661 {
2662         int i;
2663         isl_union_map *umap;
2664
2665         if (!sched)
2666                 return NULL;
2667
2668         umap = isl_union_map_empty(isl_space_copy(sched->dim));
2669         for (i = 0; i < sched->n; ++i)
2670                 umap = isl_union_map_add_map(umap,
2671                                             isl_map_copy(sched->node[i].sched));
2672
2673         return umap;
2674 }
2675
2676 static __isl_give isl_band_list *construct_band_list(
2677         __isl_keep isl_schedule *schedule, __isl_keep isl_band *parent,
2678         int band_nr, int *parent_active, int n_active);
2679
2680 /* Construct an isl_band structure for the band in the given schedule
2681  * with sequence number band_nr for the n_active nodes marked by active.
2682  * If the nodes don't have a band with the given sequence number,
2683  * then a band without members is created.
2684  *
2685  * Because of the way the schedule is constructed, we know that
2686  * the position of the band inside the schedule of a node is the same
2687  * for all active nodes.
2688  */
2689 static __isl_give isl_band *construct_band(__isl_keep isl_schedule *schedule,
2690         __isl_keep isl_band *parent,
2691         int band_nr, int *active, int n_active)
2692 {
2693         int i, j;
2694         isl_ctx *ctx = isl_schedule_get_ctx(schedule);
2695         isl_band *band;
2696         unsigned start, end;
2697
2698         band = isl_calloc_type(ctx, isl_band);
2699         if (!band)
2700                 return NULL;
2701
2702         band->ref = 1;
2703         band->schedule = schedule;
2704         band->parent = parent;
2705
2706         for (i = 0; i < schedule->n; ++i)
2707                 if (active[i] && schedule->node[i].n_band > band_nr + 1)
2708                         break;
2709
2710         if (i < schedule->n) {
2711                 band->children = construct_band_list(schedule, band,
2712                                                 band_nr + 1, active, n_active);
2713                 if (!band->children)
2714                         goto error;
2715         }
2716
2717         for (i = 0; i < schedule->n; ++i)
2718                 if (active[i])
2719                         break;
2720
2721         if (i >= schedule->n)
2722                 isl_die(ctx, isl_error_internal,
2723                         "band without active statements", goto error);
2724
2725         start = band_nr ? schedule->node[i].band_end[band_nr - 1] : 0;
2726         end = band_nr < schedule->node[i].n_band ?
2727                 schedule->node[i].band_end[band_nr] : start;
2728         band->n = end - start;
2729
2730         band->zero = isl_alloc_array(ctx, int, band->n);
2731         if (!band->zero)
2732                 goto error;
2733
2734         for (j = 0; j < band->n; ++j)
2735                 band->zero[j] = schedule->node[i].zero[start + j];
2736
2737         band->map = isl_union_map_empty(isl_space_copy(schedule->dim));
2738         for (i = 0; i < schedule->n; ++i) {
2739                 isl_map *map;
2740                 unsigned n_out;
2741
2742                 if (!active[i])
2743                         continue;
2744
2745                 map = isl_map_copy(schedule->node[i].sched);
2746                 n_out = isl_map_dim(map, isl_dim_out);
2747                 map = isl_map_project_out(map, isl_dim_out, end, n_out - end);
2748                 map = isl_map_project_out(map, isl_dim_out, 0, start);
2749                 band->map = isl_union_map_union(band->map,
2750                                                 isl_union_map_from_map(map));
2751         }
2752         if (!band->map)
2753                 goto error;
2754
2755         return band;
2756 error:
2757         isl_band_free(band);
2758         return NULL;
2759 }
2760
2761 /* Construct a list of bands that start at the same position (with
2762  * sequence number band_nr) in the schedules of the nodes that
2763  * were active in the parent band.
2764  *
2765  * A separate isl_band structure is created for each band_id
2766  * and for each node that does not have a band with sequence
2767  * number band_nr.  In the latter case, a band without members
2768  * is created.
2769  * This ensures that if a band has any children, then each node
2770  * that was active in the band is active in exactly one of the children.
2771  */
2772 static __isl_give isl_band_list *construct_band_list(
2773         __isl_keep isl_schedule *schedule, __isl_keep isl_band *parent,
2774         int band_nr, int *parent_active, int n_active)
2775 {
2776         int i, j;
2777         isl_ctx *ctx = isl_schedule_get_ctx(schedule);
2778         int *active;
2779         int n_band;
2780         isl_band_list *list;
2781
2782         n_band = 0;
2783         for (i = 0; i < n_active; ++i) {
2784                 for (j = 0; j < schedule->n; ++j) {
2785                         if (!parent_active[j])
2786                                 continue;
2787                         if (schedule->node[j].n_band <= band_nr)
2788                                 continue;
2789                         if (schedule->node[j].band_id[band_nr] == i) {
2790                                 n_band++;
2791                                 break;
2792                         }
2793                 }
2794         }
2795         for (j = 0; j < schedule->n; ++j)
2796                 if (schedule->node[j].n_band <= band_nr)
2797                         n_band++;
2798
2799         if (n_band == 1) {
2800                 isl_band *band;
2801                 list = isl_band_list_alloc(ctx, n_band);
2802                 band = construct_band(schedule, parent, band_nr,
2803                                         parent_active, n_active);
2804                 return isl_band_list_add(list, band);
2805         }
2806
2807         active = isl_alloc_array(ctx, int, schedule->n);
2808         if (!active)
2809                 return NULL;
2810
2811         list = isl_band_list_alloc(ctx, n_band);
2812
2813         for (i = 0; i < n_active; ++i) {
2814                 int n = 0;
2815                 isl_band *band;
2816
2817                 for (j = 0; j < schedule->n; ++j) {
2818                         active[j] = parent_active[j] &&
2819                                         schedule->node[j].n_band > band_nr &&
2820                                         schedule->node[j].band_id[band_nr] == i;
2821                         if (active[j])
2822                                 n++;
2823                 }
2824                 if (n == 0)
2825                         continue;
2826
2827                 band = construct_band(schedule, parent, band_nr, active, n);
2828
2829                 list = isl_band_list_add(list, band);
2830         }
2831         for (i = 0; i < schedule->n; ++i) {
2832                 isl_band *band;
2833                 if (!parent_active[i])
2834                         continue;
2835                 if (schedule->node[i].n_band > band_nr)
2836                         continue;
2837                 for (j = 0; j < schedule->n; ++j)
2838                         active[j] = j == i;
2839                 band = construct_band(schedule, parent, band_nr, active, 1);
2840                 list = isl_band_list_add(list, band);
2841         }
2842
2843         free(active);
2844
2845         return list;
2846 }
2847
2848 /* Construct a band forest representation of the schedule and
2849  * return the list of roots.
2850  */
2851 static __isl_give isl_band_list *construct_forest(
2852         __isl_keep isl_schedule *schedule)
2853 {
2854         int i;
2855         isl_ctx *ctx = isl_schedule_get_ctx(schedule);
2856         isl_band_list *forest;
2857         int *active;
2858
2859         active = isl_alloc_array(ctx, int, schedule->n);
2860         if (!active)
2861                 return NULL;
2862
2863         for (i = 0; i < schedule->n; ++i)
2864                 active[i] = 1;
2865
2866         forest = construct_band_list(schedule, NULL, 0, active, schedule->n);
2867
2868         free(active);
2869
2870         return forest;
2871 }
2872
2873 /* Return the roots of a band forest representation of the schedule.
2874  */
2875 __isl_give isl_band_list *isl_schedule_get_band_forest(
2876         __isl_keep isl_schedule *schedule)
2877 {
2878         if (!schedule)
2879                 return NULL;
2880         if (!schedule->band_forest)
2881                 schedule->band_forest = construct_forest(schedule);
2882         return isl_band_list_dup(schedule->band_forest);
2883 }
2884
2885 static __isl_give isl_printer *print_band_list(__isl_take isl_printer *p,
2886         __isl_keep isl_band_list *list);
2887
2888 static __isl_give isl_printer *print_band(__isl_take isl_printer *p,
2889         __isl_keep isl_band *band)
2890 {
2891         isl_band_list *children;
2892
2893         p = isl_printer_start_line(p);
2894         p = isl_printer_print_union_map(p, band->map);
2895         p = isl_printer_end_line(p);
2896
2897         if (!isl_band_has_children(band))
2898                 return p;
2899
2900         children = isl_band_get_children(band);
2901
2902         p = isl_printer_indent(p, 4);
2903         p = print_band_list(p, children);
2904         p = isl_printer_indent(p, -4);
2905
2906         isl_band_list_free(children);
2907
2908         return p;
2909 }
2910
2911 static __isl_give isl_printer *print_band_list(__isl_take isl_printer *p,
2912         __isl_keep isl_band_list *list)
2913 {
2914         int i, n;
2915
2916         n = isl_band_list_n_band(list);
2917         for (i = 0; i < n; ++i) {
2918                 isl_band *band;
2919                 band = isl_band_list_get_band(list, i);
2920                 p = print_band(p, band);
2921                 isl_band_free(band);
2922         }
2923
2924         return p;
2925 }
2926
2927 __isl_give isl_printer *isl_printer_print_schedule(__isl_take isl_printer *p,
2928         __isl_keep isl_schedule *schedule)
2929 {
2930         isl_band_list *forest;
2931
2932         forest = isl_schedule_get_band_forest(schedule);
2933
2934         p = print_band_list(p, forest);
2935
2936         isl_band_list_free(forest);
2937
2938         return p;
2939 }
2940
2941 void isl_schedule_dump(__isl_keep isl_schedule *schedule)
2942 {
2943         isl_printer *printer;
2944
2945         if (!schedule)
2946                 return;
2947
2948         printer = isl_printer_to_file(isl_schedule_get_ctx(schedule), stderr);
2949         printer = isl_printer_print_schedule(printer, schedule);
2950
2951         isl_printer_free(printer);
2952 }