isl backend: remove dependence on internal represenation of isl_constraint
[cloog.git] / source / isl / domain.c
blob9e5df1246004fe60826d2888709879d2bbfcc255
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <cloog/isl/cloog.h>
7 #include <isl/list.h>
8 #include <isl/constraint.h>
9 #include <isl/div.h>
10 #include <isl/ilp.h>
11 #include <isl/aff.h>
13 CloogDomain *cloog_domain_from_isl_set(struct isl_set *set)
15 set = isl_set_detect_equalities(set);
16 set = isl_set_compute_divs(set);
17 return (CloogDomain *)set;
20 __isl_give isl_set *isl_set_from_cloog_domain(CloogDomain *domain)
22 return (isl_set *)domain;
25 CloogScattering *cloog_scattering_from_isl_map(struct isl_map *map)
27 return (CloogScattering *)map;
30 __isl_give isl_map *isl_map_from_cloog_scattering(CloogScattering *scattering)
32 return (isl_map *)scattering;
36 /**
37 * Returns true if each scattering dimension is defined in terms
38 * of the original iterators.
40 int cloog_scattering_fully_specified(CloogScattering *scattering,
41 CloogDomain *domain)
43 isl_map *map = isl_map_from_cloog_scattering(scattering);
44 return isl_map_is_single_valued(map);
48 CloogConstraintSet *cloog_domain_constraints(CloogDomain *domain)
50 isl_basic_set *bset;
51 isl_set *set = isl_set_from_cloog_domain(domain);
52 assert(isl_set_n_basic_set(set) == 1);
53 bset = isl_set_copy_basic_set(set);
54 return cloog_constraint_set_from_isl_basic_set(bset);
58 void cloog_domain_print_constraints(FILE *foo, CloogDomain *domain,
59 int print_number)
61 isl_basic_set *bset;
62 isl_set *set = isl_set_from_cloog_domain(domain);
64 if (print_number)
65 isl_set_print(set, foo, 0, ISL_FORMAT_EXT_POLYLIB);
66 else {
67 assert(isl_set_n_basic_set(set) == 1);
68 bset = isl_set_copy_basic_set(set);
69 isl_basic_set_print(bset, foo,
70 0, NULL, NULL, ISL_FORMAT_POLYLIB);
71 isl_basic_set_free(bset);
76 void cloog_scattering_print_constraints(FILE *foo, CloogScattering *scattering)
78 isl_map *map = isl_map_from_cloog_scattering(scattering);
79 isl_map_print(map, foo, 0, ISL_FORMAT_EXT_POLYLIB);
83 void cloog_domain_free(CloogDomain * domain)
85 isl_set *set = isl_set_from_cloog_domain(domain);
86 isl_set_free(set);
90 void cloog_scattering_free(CloogScattering *scatt)
92 isl_map *map = isl_map_from_cloog_scattering(scatt);
93 isl_map_free(map);
97 CloogDomain * cloog_domain_copy(CloogDomain * domain)
99 isl_set *set = isl_set_from_cloog_domain(domain);
100 return cloog_domain_from_isl_set(isl_set_copy(set));
105 * cloog_domain_convex function:
106 * Computes the convex hull of domain.
108 CloogDomain *cloog_domain_convex(CloogDomain *domain)
110 isl_set *set = isl_set_from_cloog_domain(domain);
111 set = isl_set_from_basic_set(isl_set_convex_hull(isl_set_copy(set)));
112 return cloog_domain_from_isl_set(set);
117 * cloog_domain_simple_convex:
118 * Given a list (union) of polyhedra, this function returns a "simple"
119 * convex hull of this union. In particular, the constraints of the
120 * the returned polyhedron consist of (parametric) lower and upper
121 * bounds on individual variables and constraints that appear in the
122 * original polyhedra.
124 CloogDomain *cloog_domain_simple_convex(CloogDomain *domain)
126 struct isl_basic_set *hull;
127 isl_set *set = isl_set_from_cloog_domain(domain);
129 if (cloog_domain_isconvex(domain))
130 return cloog_domain_copy(domain);
132 hull = isl_set_bounded_simple_hull(isl_set_copy(set));
133 return cloog_domain_from_isl_set(isl_set_from_basic_set(hull));
138 * cloog_domain_simplify function:
139 * Given two polyhedral domains (dom1) and (dom2),
140 * this function finds the largest domain set (or the smallest list
141 * of non-redundant constraints), that when intersected with polyhedral
142 * domain (dom2) equals (dom1)intersect(dom2). The output is a new CloogDomain
143 * structure with a polyhedral domain with the "redundant" constraints removed.
144 * NB: the second domain is required not to be a union.
146 CloogDomain *cloog_domain_simplify(CloogDomain *dom1, CloogDomain *dom2)
148 isl_set *set1 = isl_set_from_cloog_domain(dom1);
149 isl_set *set2 = isl_set_from_cloog_domain(dom2);
150 set1 = isl_set_gist(isl_set_copy(set1), isl_set_copy(set2));
151 return cloog_domain_from_isl_set(set1);
156 * cloog_domain_union function:
157 * This function returns a new polyhedral domain which is the union of
158 * two polyhedral domains (dom1) U (dom2).
159 * Frees dom1 and dom2;
161 CloogDomain *cloog_domain_union(CloogDomain *dom1, CloogDomain *dom2)
163 isl_set *set1 = isl_set_from_cloog_domain(dom1);
164 isl_set *set2 = isl_set_from_cloog_domain(dom2);
165 set1 = isl_set_union(set1, set2);
166 return cloog_domain_from_isl_set(set1);
172 * cloog_domain_intersection function:
173 * This function returns a new polyhedral domain which is the intersection of
174 * two polyhedral domains (dom1) \cap (dom2).
176 CloogDomain *cloog_domain_intersection(CloogDomain *dom1, CloogDomain *dom2)
178 isl_set *set1 = isl_set_from_cloog_domain(dom1);
179 isl_set *set2 = isl_set_from_cloog_domain(dom2);
180 set1 = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
181 return cloog_domain_from_isl_set(set1);
186 * cloog_domain_difference function:
187 * Returns the set difference domain \ minus.
189 CloogDomain *cloog_domain_difference(CloogDomain *domain, CloogDomain *minus)
191 isl_set *set1 = isl_set_from_cloog_domain(domain);
192 isl_set *set2 = isl_set_from_cloog_domain(minus);
193 set1 = isl_set_subtract(isl_set_copy(set1), isl_set_copy(set2));
194 return cloog_domain_from_isl_set(set1);
199 * cloog_domain_sort function:
200 * This function topologically sorts (nb_doms) domains. Here (doms) is an
201 * array of pointers to CloogDomains, (nb_doms) is the number of domains,
202 * (level) is the level to consider for partial ordering (nb_par) is the
203 * parameter space dimension, (permut) if not NULL, is an array of (nb_doms)
204 * integers that contains a permutation specification after call in order to
205 * apply the topological sorting.
207 void cloog_domain_sort(CloogDomain **doms, unsigned nb_doms, unsigned level,
208 int *permut)
210 int i, j, k, cmp;
211 struct isl_ctx *ctx;
212 unsigned char **follows;
213 isl_set *set_i, *set_j;
214 isl_basic_set *bset_i, *bset_j;
216 if (!nb_doms)
217 return;
218 set_i = isl_set_from_cloog_domain(doms[0]);
219 ctx = isl_set_get_ctx(set_i);
220 for (i = 0; i < nb_doms; i++) {
221 set_i = isl_set_from_cloog_domain(doms[i]);
222 assert(isl_set_n_basic_set(set_i) == 1);
225 follows = isl_alloc_array(ctx, unsigned char *, nb_doms);
226 assert(follows);
227 for (i = 0; i < nb_doms; ++i) {
228 follows[i] = isl_alloc_array(ctx, unsigned char, nb_doms);
229 assert(follows[i]);
230 for (j = 0; j < nb_doms; ++j)
231 follows[i][j] = 0;
234 for (i = 1; i < nb_doms; ++i) {
235 for (j = 0; j < i; ++j) {
236 if (follows[i][j] || follows[j][i])
237 continue;
238 set_i = isl_set_from_cloog_domain(doms[i]);
239 set_j = isl_set_from_cloog_domain(doms[j]);
240 bset_i = isl_set_copy_basic_set(set_i);
241 bset_j = isl_set_copy_basic_set(set_j);
242 cmp = isl_basic_set_compare_at(bset_i, bset_j, level-1);
243 isl_basic_set_free(bset_i);
244 isl_basic_set_free(bset_j);
245 if (!cmp)
246 continue;
247 if (cmp > 0) {
248 follows[i][j] = 1;
249 for (k = 0; k < i; ++k)
250 follows[i][k] |= follows[j][k];
251 } else {
252 follows[j][i] = 1;
253 for (k = 0; k < i; ++k)
254 follows[k][i] |= follows[k][j];
259 for (i = 0, j = 0; i < nb_doms; j = (j + 1) % nb_doms) {
260 for (k = 0; k < nb_doms; ++k)
261 if (follows[j][k])
262 break;
263 if (k < nb_doms)
264 continue;
265 for (k = 0; k < nb_doms; ++k)
266 follows[k][j] = 0;
267 follows[j][j] = 1;
268 permut[i] = 1 + j;
269 ++i;
272 for (i = 0; i < nb_doms; ++i)
273 free(follows[i]);
274 free(follows);
279 * Check whether there is or may be any value of dom1 at the given level
280 * that is greater than or equal to a value of dom2 at the same level.
282 * Return
283 * 1 is there is or may be a greater-than pair.
284 * 0 if there is no greater-than pair, but there may be an equal-to pair
285 * -1 if there is definitely no such pair
287 int cloog_domain_follows(CloogDomain *dom1, CloogDomain *dom2, unsigned level)
289 isl_set *set1 = isl_set_from_cloog_domain(dom1);
290 isl_set *set2 = isl_set_from_cloog_domain(dom2);
291 int follows;
293 follows = isl_set_follows_at(set1, set2, level - 1);
294 assert(follows >= -1);
296 return follows;
301 * cloog_domain_empty function:
302 * Returns an empty domain of the same dimensions as template.
304 CloogDomain *cloog_domain_empty(CloogDomain *template)
306 isl_set *set = isl_set_from_cloog_domain(template);
307 return cloog_domain_from_isl_set(isl_set_empty_like(set));
312 * Return 1 if the specified dimension has both an upper and a lower bound.
314 int cloog_domain_is_bounded(CloogDomain *dom, unsigned level)
316 isl_set *set = isl_set_from_cloog_domain(dom);
317 return isl_set_dim_is_bounded(set, isl_dim_set, level - 1);
321 /******************************************************************************
322 * Structure display function *
323 ******************************************************************************/
327 * cloog_domain_print_structure :
328 * this function is a more human-friendly way to display the CloogDomain data
329 * structure, it only shows the constraint system and includes an indentation
330 * level (level) in order to work with others print_structure functions.
332 void cloog_domain_print_structure(FILE *file, CloogDomain *domain, int level,
333 const char *name)
335 int i ;
336 isl_set *set = isl_set_from_cloog_domain(domain);
338 /* Go to the right level. */
339 for (i = 0; i < level; i++)
340 fprintf(file, "|\t");
342 if (!set) {
343 fprintf(file, "+-- Null CloogDomain\n");
344 return;
346 fprintf(file, "+-- %s\n", name);
347 for (i = 0; i < level+1; ++i)
348 fprintf(file, "|\t");
350 isl_set_print(set, file, 0, ISL_FORMAT_ISL);
352 fprintf(file, "\n");
356 /******************************************************************************
357 * Memory deallocation function *
358 ******************************************************************************/
361 void cloog_domain_list_free(CloogDomainList *list)
363 CloogDomainList *next;
365 for ( ; list; list = next) {
366 next = list->next;
367 cloog_domain_free(list->domain);
368 free(list);
374 * cloog_scattering_list_free function:
375 * This function frees the allocated memory for a CloogScatteringList structure.
377 void cloog_scattering_list_free(CloogScatteringList *list)
379 while (list != NULL) {
380 CloogScatteringList *temp = list->next;
381 isl_map *map = isl_map_from_cloog_scattering(list->scatt);
382 isl_map_free(map);
383 free(list);
384 list = temp;
389 /******************************************************************************
390 * Reading function *
391 ******************************************************************************/
395 * cloog_domain_read_context function:
396 * Read parameter domain.
398 CloogDomain *cloog_domain_read_context(CloogState *state, FILE *input)
400 struct isl_ctx *ctx = state->backend->ctx;
401 isl_set *set;
403 set = isl_set_read_from_file(ctx, input, 0);
404 set = isl_set_move_dims(set, isl_dim_param, 0,
405 isl_dim_set, 0, isl_set_dim(set, isl_dim_set));
407 return cloog_domain_from_isl_set(set);
412 * cloog_domain_from_context
413 * Reinterpret context by turning parameters into variables.
415 CloogDomain *cloog_domain_from_context(CloogDomain *context)
417 isl_set *set = isl_set_from_cloog_domain(context);
419 set = isl_set_move_dims(set, isl_dim_set, 0,
420 isl_dim_param, 0, isl_set_dim(set, isl_dim_param));
422 return cloog_domain_from_isl_set(set);
427 * cloog_domain_union_read function:
428 * This function reads a union of polyhedra into a file (input) and
429 * returns a pointer to a CloogDomain containing the read information.
431 CloogDomain *cloog_domain_union_read(CloogState *state,
432 FILE *input, int nb_parameters)
434 struct isl_ctx *ctx = state->backend->ctx;
435 struct isl_set *set;
437 set = isl_set_read_from_file(ctx, input, nb_parameters);
438 return cloog_domain_from_isl_set(set);
443 * cloog_domain_read_scattering function:
444 * This function reads in a scattering function from the file input.
446 * We try to read the scattering relation as a map, but if it is
447 * specified in the original PolyLib format, then isl_map_read_from_file
448 * will treat the input as a set return a map with zero input dimensions.
449 * In this case, we need to decompose the set into a map from
450 * scattering dimensions to domain dimensions and then invert the
451 * resulting map.
453 CloogScattering *cloog_domain_read_scattering(CloogDomain *domain, FILE *input)
455 isl_set *set = isl_set_from_cloog_domain(domain);
456 isl_ctx *ctx = isl_set_get_ctx(set);
457 struct isl_map *scat;
458 unsigned nparam;
459 unsigned dim;
460 unsigned n_scat;
462 dim = isl_set_dim(set, isl_dim_set);
463 nparam = isl_set_dim(set, isl_dim_param);
464 scat = isl_map_read_from_file(ctx, input, nparam);
465 if (isl_map_dim(scat, isl_dim_in) != dim) {
466 n_scat = isl_map_dim(scat, isl_dim_out) - dim;
467 scat = isl_map_move_dims(scat, isl_dim_in, 0,
468 isl_dim_out, n_scat, dim);
470 return cloog_scattering_from_isl_map(scat);
473 /******************************************************************************
474 * CloogMatrix Reading function *
475 ******************************************************************************/
478 * isl_constraint_read_from_matrix:
479 * Convert a single line of a matrix to a isl_constraint.
480 * Returns a pointer to the constraint if successful; NULL otherwise.
482 static struct isl_constraint *isl_constraint_read_from_matrix(
483 struct isl_dim *dim, cloog_int_t *row)
485 struct isl_constraint *constraint;
486 int j;
487 int nvariables = isl_dim_size(dim, isl_dim_set);
488 int nparam = isl_dim_size(dim, isl_dim_param);
490 if (cloog_int_is_zero(row[0]))
491 constraint = isl_equality_alloc(dim);
492 else
493 constraint = isl_inequality_alloc(dim);
495 for (j = 0; j < nvariables; ++j)
496 isl_constraint_set_coefficient(constraint, isl_dim_out, j,
497 row[1 + j]);
499 for (j = 0; j < nparam; ++j)
500 isl_constraint_set_coefficient(constraint, isl_dim_param, j,
501 row[1 + nvariables + j]);
503 isl_constraint_set_constant(constraint, row[1 + nvariables + nparam]);
505 return constraint;
509 * isl_basic_set_read_from_matrix:
510 * Convert matrix to basic_set. The matrix contains nparam parameter columns.
511 * Returns a pointer to the basic_set if successful; NULL otherwise.
513 static struct isl_basic_set *isl_basic_set_read_from_matrix(struct isl_ctx *ctx,
514 CloogMatrix* matrix, int nparam)
516 struct isl_dim *dim;
517 struct isl_basic_set *bset;
518 int i;
519 unsigned nrows, ncolumns;
521 nrows = matrix->NbRows;
522 ncolumns = matrix->NbColumns;
523 int nvariables = ncolumns - 2 - nparam;
525 dim = isl_dim_set_alloc(ctx, nparam, nvariables);
527 bset = isl_basic_set_universe(isl_dim_copy(dim));
529 for (i = 0; i < nrows; ++i) {
530 cloog_int_t *row = matrix->p[i];
531 struct isl_constraint *constraint =
532 isl_constraint_read_from_matrix(isl_dim_copy(dim), row);
533 bset = isl_basic_set_add_constraint(bset, constraint);
536 isl_dim_free(dim);
538 return bset;
542 * cloog_domain_from_cloog_matrix:
543 * Create a CloogDomain containing the constraints described in matrix.
544 * nparam is the number of parameters contained in the domain.
545 * Returns a pointer to the CloogDomain if successful; NULL otherwise.
547 CloogDomain *cloog_domain_from_cloog_matrix(CloogState *state,
548 CloogMatrix *matrix, int nparam)
550 struct isl_ctx *ctx = state->backend->ctx;
551 struct isl_basic_set *bset;
553 bset = isl_basic_set_read_from_matrix(ctx, matrix, nparam);
555 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
559 * cloog_scattering_from_cloog_matrix:
560 * Create a CloogScattering containing the constraints described in matrix.
561 * nparam is the number of parameters contained in the domain.
562 * Returns a pointer to the CloogScattering if successful; NULL otherwise.
564 CloogScattering *cloog_scattering_from_cloog_matrix(CloogState *state,
565 CloogMatrix *matrix, int nb_scat, int nb_par)
567 struct isl_ctx *ctx = state->backend->ctx;
568 struct isl_basic_set *bset;
569 struct isl_basic_map *scat;
570 struct isl_dim *dims;
571 unsigned dim;
573 bset = isl_basic_set_read_from_matrix(ctx, matrix, nb_par);
574 dim = isl_basic_set_n_dim(bset) - nb_scat;
575 dims = isl_dim_alloc(ctx, nb_par, nb_scat, dim);
577 scat = isl_basic_map_from_basic_set(bset, dims);
578 scat = isl_basic_map_reverse(scat);
579 return cloog_scattering_from_isl_map(isl_map_from_basic_map(scat));
583 /******************************************************************************
584 * Processing functions *
585 ******************************************************************************/
590 * cloog_domain_isempty function:
592 int cloog_domain_isempty(CloogDomain *domain)
594 isl_set *set = isl_set_from_cloog_domain(domain);
595 return isl_set_is_empty(set);
600 * cloog_domain_universe function:
601 * This function returns the complete dim-dimensional space.
603 CloogDomain *cloog_domain_universe(CloogState *state, unsigned dim)
605 struct isl_dim *dims;
606 struct isl_basic_set *bset;
608 dims = isl_dim_set_alloc(state->backend->ctx, 0, dim);
609 bset = isl_basic_set_universe(dims);
610 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
615 * cloog_domain_project function:
616 * This function returns the projection of
617 * (domain) on the (level) first dimensions (i.e. outer loops).
619 CloogDomain *cloog_domain_project(CloogDomain *domain, int level)
621 isl_set *set = isl_set_from_cloog_domain(domain);
622 set = isl_set_remove_dims(isl_set_copy(set), isl_dim_set,
623 level, isl_set_n_dim(set) - level);
624 set = isl_set_compute_divs(set);
625 if (level > 0)
626 set = isl_set_remove_divs_involving_dims(set,
627 isl_dim_set, level - 1, 1);
628 return cloog_domain_from_isl_set(set);
633 * cloog_domain_extend function:
634 * This function returns the (domain) given as input with (dim)
635 * dimensions and (nb_par) parameters.
636 * This function does not free (domain), and returns a new CloogDomain.
638 CloogDomain *cloog_domain_extend(CloogDomain *domain, int dim)
640 isl_set *set = isl_set_from_cloog_domain(domain);
641 set = isl_set_extend(isl_set_copy(set), isl_set_n_param(set), dim);
642 return cloog_domain_from_isl_set(set);
647 * cloog_domain_never_integral function:
648 * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0.
649 * There is no need to check for such constraints explicitly for the isl
650 * backend.
652 int cloog_domain_never_integral(CloogDomain * domain)
654 isl_set *set = isl_set_from_cloog_domain(domain);
655 return isl_set_is_empty(set);
660 * Check whether the loop at "level" is executed at most once.
661 * We construct a map that maps all remaining variables to this iterator
662 * and check whether this map is single valued.
664 * Alternatively, we could have mapped the domain through a mapping
665 * [p] -> { [..., i] -> [..., i'] : i' > i }
666 * and then taken the intersection of the original domain and the transformed
667 * domain. If this intersection is empty, then the corresponding
668 * loop is executed at most once.
670 int cloog_domain_is_otl(CloogDomain *domain, int level)
672 int otl;
673 isl_set *set = isl_set_from_cloog_domain(domain);
674 isl_map *map;
676 map = isl_map_from_domain(isl_set_copy(set));
677 map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_in, level - 1, 1);
678 otl = isl_map_is_single_valued(map);
679 isl_map_free(map);
681 return otl;
686 * cloog_domain_stride function:
687 * This function finds the stride imposed to unknown with the column number
688 * 'strided_level' in order to be integral. For instance, if we have a
689 * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral
690 * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to
691 * the unknown i. The function returns the imposed stride in a parameter field.
692 * - domain is the set of constraint we have to consider,
693 * - strided_level is the column number of the unknown for which a stride have
694 * to be found,
695 * - looking_level is the column number of the unknown that impose a stride to
696 * the first unknown.
697 * - stride is the stride that is returned back as a function parameter.
698 * - offset is the value of the constant c if the condition is of the shape
699 * (i + c)%s = 0, s being the stride.
701 void cloog_domain_stride(CloogDomain *domain, int strided_level,
702 cloog_int_t *stride, cloog_int_t *offset)
704 isl_set *set = isl_set_from_cloog_domain(domain);
705 isl_set_dim_residue_class(set, strided_level - 1, stride, offset);
706 if (!isl_int_is_zero(*offset))
707 isl_int_sub(*offset, *stride, *offset);
708 return;
712 struct cloog_can_stride {
713 int level;
714 int can_stride;
717 static int constraint_can_stride(__isl_take isl_constraint *c, void *user)
719 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
720 int i;
721 isl_int v;
722 unsigned n_div;
724 if (isl_constraint_is_equality(c)) {
725 isl_constraint_free(c);
726 return 0;
729 isl_int_init(v);
730 isl_constraint_get_coefficient(c, isl_dim_set, ccs->level - 1, &v);
731 if (isl_int_is_pos(v)) {
732 n_div = isl_constraint_dim(c, isl_dim_div);
733 for (i = 0; i < n_div; ++i) {
734 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
735 if (!isl_int_is_zero(v))
736 break;
738 if (i < n_div)
739 ccs->can_stride = 0;
741 isl_int_clear(v);
742 isl_constraint_free(c);
744 return 0;
747 static int basic_set_can_stride(__isl_take isl_basic_set *bset, void *user)
749 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
750 int r;
752 r = isl_basic_set_foreach_constraint(bset, constraint_can_stride, ccs);
753 isl_basic_set_free(bset);
754 return r;
759 * Return 1 if CLooG is allowed to perform stride detection on level "level"
760 * and 0 otherwise.
761 * Currently, stride detection is only allowed when none of the lower
762 * bound constraints involve any existentially quantified variables.
763 * The reason is that the current isl interface does not make it
764 * easy to construct an integer division that depends on other integer
765 * divisions.
766 * By not allowing existentially quantified variables in the constraints,
767 * we can ignore them in cloog_domain_stride_lower_bound.
769 int cloog_domain_can_stride(CloogDomain *domain, int level)
771 struct cloog_can_stride ccs = { level, 1 };
772 isl_set *set = isl_set_from_cloog_domain(domain);
773 int r;
774 r = isl_set_foreach_basic_set(set, basic_set_can_stride, &ccs);
775 assert(r == 0);
776 return ccs.can_stride;
780 struct cloog_stride_lower {
781 int level;
782 CloogStride *stride;
783 isl_set *set;
784 isl_basic_set *bounds;
787 /* If the given constraint is a lower bound on csl->level, then add
788 * a lower bound to csl->bounds that makes sure that the remainder
789 * of the smallest value on division by csl->stride is equal to csl->offset.
791 * In particular, the given lower bound is of the form
793 * a i + f >= 0
795 * where f may depend on the parameters and other iterators.
796 * The stride is s and the offset is d.
797 * The lower bound -f/a may not satisfy the above condition. In fact,
798 * it may not even be integral. We want to round this value of i up
799 * to the nearest value that satisfies the condition and add the corresponding
800 * lower bound constraint. This nearest value is obtained by rounding
801 * i - d up to the nearest multiple of s.
802 * That is, we first subtract d
804 * i' = -f/a - d
806 * then we round up to the nearest multiple of s
808 * i'' = s * ceil(i'/s)
810 * and finally, we add d again
812 * i''' = i'' + d
814 * and impose the constraint i >= i'''.
816 * We find
818 * i'' = s * ceil((-f - a * d)/(a * s)) = - s * floor((f + a * d)/(a * s))
820 * i >= - s * floor((f + a * d)/(a * s)) + d
822 * or
823 * i + s * floor((f + a * d)/(a * s)) - d >= 0
825 static int constraint_stride_lower(__isl_take isl_constraint *c, void *user)
827 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
828 int i;
829 isl_int v;
830 isl_int t;
831 isl_constraint *bound;
832 isl_div *div;
833 int pos;
834 unsigned nparam, nvar;
836 if (isl_constraint_is_equality(c)) {
837 isl_constraint_free(c);
838 return 0;
841 isl_int_init(v);
842 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
843 if (!isl_int_is_pos(v)) {
844 isl_int_clear(v);
845 isl_constraint_free(c);
847 return 0;
850 isl_int_init(t);
852 nparam = isl_constraint_dim(c, isl_dim_param);
853 nvar = isl_constraint_dim(c, isl_dim_set);
854 bound = isl_inequality_alloc(isl_basic_set_get_dim(csl->bounds));
855 div = isl_div_alloc(isl_basic_set_get_dim(csl->bounds));
856 isl_int_mul(t, v, csl->stride->stride);
857 isl_div_set_denominator(div, t);
858 for (i = 0; i < nparam; ++i) {
859 isl_constraint_get_coefficient(c, isl_dim_param, i, &t);
860 isl_div_set_coefficient(div, isl_dim_param, i, t);
862 for (i = 0; i < nvar; ++i) {
863 if (i == csl->level - 1)
864 continue;
865 isl_constraint_get_coefficient(c, isl_dim_set, i, &t);
866 isl_div_set_coefficient(div, isl_dim_set, i, t);
868 isl_constraint_get_constant(c, &t);
869 isl_int_addmul(t, v, csl->stride->offset);
870 isl_div_set_constant(div, t);
872 bound = isl_constraint_add_div(bound, div, &pos);
873 isl_int_set_si(t, 1);
874 isl_constraint_set_coefficient(bound, isl_dim_set,
875 csl->level - 1, t);
876 isl_constraint_set_coefficient(bound, isl_dim_div, pos,
877 csl->stride->stride);
878 isl_int_neg(t, csl->stride->offset);
879 isl_constraint_set_constant(bound, t);
880 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
882 isl_int_clear(v);
883 isl_int_clear(t);
884 isl_constraint_free(c);
886 return 0;
889 /* This functions performs essentially the same operation as
890 * constraint_stride_lower, the only difference being that the offset d
891 * is not a constant, but an affine expression in terms of the parameters
892 * and earlier variables. In particular the affine expression is equal
893 * to the coefficients of stride->constraint multiplied by stride->factor.
894 * As in constraint_stride_lower, we add an extra bound
896 * i + s * floor((f + a * d)/(a * s)) - d >= 0
898 * for each lower bound
900 * a i + f >= 0
902 * where d is not the aforementioned affine expression.
904 static int constraint_stride_lower_c(__isl_take isl_constraint *c, void *user)
906 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
907 int i;
908 isl_int v;
909 isl_int t, u;
910 isl_constraint *bound;
911 isl_constraint *csl_c;
912 isl_div *div;
913 int pos;
914 unsigned nparam, nvar;
916 if (isl_constraint_is_equality(c)) {
917 isl_constraint_free(c);
918 return 0;
921 isl_int_init(v);
922 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
923 if (!isl_int_is_pos(v)) {
924 isl_int_clear(v);
925 isl_constraint_free(c);
927 return 0;
930 csl_c = cloog_constraint_to_isl(csl->stride->constraint);
932 isl_int_init(t);
933 isl_int_init(u);
935 nparam = isl_constraint_dim(c, isl_dim_param);
936 nvar = isl_constraint_dim(c, isl_dim_set);
937 bound = isl_inequality_alloc(isl_basic_set_get_dim(csl->bounds));
938 div = isl_div_alloc(isl_basic_set_get_dim(csl->bounds));
939 isl_int_mul(t, v, csl->stride->stride);
940 isl_div_set_denominator(div, t);
941 for (i = 0; i < nparam; ++i) {
942 isl_constraint_get_coefficient(c, isl_dim_param, i, &t);
943 isl_constraint_get_coefficient(csl_c, isl_dim_param, i, &u);
944 isl_int_mul(u, u, csl->stride->factor);
945 isl_int_addmul(t, v, u);
946 isl_div_set_coefficient(div, isl_dim_param, i, t);
947 isl_int_neg(u, u);
948 isl_constraint_set_coefficient(bound, isl_dim_param, i, u);
950 for (i = 0; i < nvar; ++i) {
951 if (i == csl->level - 1)
952 continue;
953 isl_constraint_get_coefficient(c, isl_dim_set, i, &t);
954 isl_constraint_get_coefficient(csl_c, isl_dim_set, i, &u);
955 isl_int_mul(u, u, csl->stride->factor);
956 isl_int_addmul(t, v, u);
957 isl_div_set_coefficient(div, isl_dim_set, i, t);
958 isl_int_neg(u, u);
959 isl_constraint_set_coefficient(bound, isl_dim_set, i, u);
961 isl_constraint_get_constant(c, &t);
962 isl_constraint_get_constant(csl_c, &u);
963 isl_int_mul(u, u, csl->stride->factor);
964 isl_int_addmul(t, v, u);
965 isl_div_set_constant(div, t);
966 isl_int_neg(u, u);
967 isl_constraint_set_constant(bound, u);
969 bound = isl_constraint_add_div(bound, div, &pos);
970 isl_int_set_si(t, 1);
971 isl_constraint_set_coefficient(bound, isl_dim_set,
972 csl->level - 1, t);
973 isl_constraint_set_coefficient(bound, isl_dim_div, pos,
974 csl->stride->stride);
975 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
977 isl_int_clear(u);
978 isl_int_clear(t);
979 isl_int_clear(v);
980 isl_constraint_free(c);
982 return 0;
985 static int basic_set_stride_lower(__isl_take isl_basic_set *bset, void *user)
987 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
988 int r;
990 csl->bounds = isl_basic_set_universe_like(bset);
991 if (csl->stride->constraint)
992 r = isl_basic_set_foreach_constraint(bset,
993 &constraint_stride_lower_c, csl);
994 else
995 r = isl_basic_set_foreach_constraint(bset,
996 &constraint_stride_lower, csl);
997 bset = isl_basic_set_intersect(bset, csl->bounds);
998 csl->set = isl_set_union(csl->set, isl_set_from_basic_set(bset));
1000 return r;
1004 * Update the lower bounds at level "level" to the given stride information.
1005 * That is, make sure that the remainder on division by "stride"
1006 * is equal to "offset".
1008 CloogDomain *cloog_domain_stride_lower_bound(CloogDomain *domain, int level,
1009 CloogStride *stride)
1011 struct cloog_stride_lower csl;
1012 isl_set *set = isl_set_from_cloog_domain(domain);
1013 int r;
1015 csl.stride = stride;
1016 csl.level = level;
1017 csl.set = isl_set_empty_like(set);
1019 r = isl_set_foreach_basic_set(set, basic_set_stride_lower, &csl);
1020 assert(r == 0);
1022 cloog_domain_free(domain);
1023 return cloog_domain_from_isl_set(csl.set);
1027 /* Add stride constraint, if any, to domain.
1029 CloogDomain *cloog_domain_add_stride_constraint(CloogDomain *domain,
1030 CloogStride *stride)
1032 isl_constraint *c;
1033 isl_set *set;
1035 if (!stride || !stride->constraint)
1036 return domain;
1038 set = isl_set_from_cloog_domain(domain);
1039 c = isl_constraint_copy(cloog_constraint_to_isl(stride->constraint));
1041 set = isl_set_add_constraint(set, c);
1043 return cloog_domain_from_isl_set(set);
1048 * cloog_domain_lazy_equal function:
1049 * This function returns 1 if the domains given as input are the same, 0 if it
1050 * is unable to decide.
1052 int cloog_domain_lazy_equal(CloogDomain *d1, CloogDomain *d2)
1054 isl_set *set1 = isl_set_from_cloog_domain(d1);
1055 isl_set *set2 = isl_set_from_cloog_domain(d2);
1056 return isl_set_fast_is_equal(set1, set2);
1059 struct cloog_bound_split {
1060 isl_set *set;
1061 int level;
1062 int lower;
1063 int upper;
1066 static int constraint_bound_split(__isl_take isl_constraint *c, void *user)
1068 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1069 isl_int v;
1070 int i;
1071 int handle = 0;
1073 isl_int_init(v);
1074 isl_constraint_get_coefficient(c, isl_dim_set, cbs->level - 1, &v);
1075 if (!cbs->lower && isl_int_is_pos(v))
1076 cbs->lower = handle = 1;
1077 else if (!cbs->upper && isl_int_is_neg(v))
1078 cbs->upper = handle = 1;
1079 if (handle) {
1080 for (i = 0; i < isl_set_dim(cbs->set, isl_dim_param); ++i) {
1081 isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
1082 if (isl_int_is_zero(v))
1083 continue;
1084 cbs->set = isl_set_split_dims(cbs->set,
1085 isl_dim_param, i, 1);
1088 isl_int_clear(v);
1089 isl_constraint_free(c);
1091 return (cbs->lower && cbs->upper) ? -1 : 0;
1094 static int basic_set_bound_split(__isl_take isl_basic_set *bset, void *user)
1096 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1097 int r;
1099 cbs->lower = 0;
1100 cbs->upper = 0;
1101 r = isl_basic_set_foreach_constraint(bset, constraint_bound_split, cbs);
1102 isl_basic_set_free(bset);
1103 return ((!cbs->lower || !cbs->upper) && r < 0) ? -1 : 0;
1107 * Return a union of sets S_i such that the convex hull of "dom",
1108 * when intersected with one the sets S_i, will have an upper and
1109 * lower bound for the dimension at "level" (provided "dom" itself
1110 * has such bounds for the dimensions).
1112 * We currently take a very simple approach. For each of the basic
1113 * sets in "dom" we pick a lower and an upper bound and split the
1114 * range of any parameter involved in these two bounds in a
1115 * nonnegative and a negative part. This ensures that the symbolic
1116 * constant in these two constraints are themselves bounded and
1117 * so there will be at least one upper and one lower bound
1118 * in the convex hull.
1120 CloogDomain *cloog_domain_bound_splitter(CloogDomain *dom, int level)
1122 struct cloog_bound_split cbs;
1123 isl_set *set = isl_set_from_cloog_domain(dom);
1124 int r;
1125 cbs.level = level;
1126 cbs.set = isl_set_universe_like(set);
1127 r = isl_set_foreach_basic_set(set, basic_set_bound_split, &cbs);
1128 assert(r == 0);
1129 return cloog_domain_from_isl_set(cbs.set);
1133 /* Check whether the union of scattering functions over all domains
1134 * is obviously injective.
1136 static int injective_scattering(CloogScatteringList *list)
1138 isl_map *map;
1139 isl_union_map *umap;
1140 int injective;
1141 int i = 0;
1142 char name[30];
1144 if (!list)
1145 return 1;
1147 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1148 snprintf(name, sizeof(name), "S%d", i);
1149 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1150 umap = isl_union_map_from_map(map);
1152 for (list = list->next, ++i; list; list = list->next, ++i) {
1153 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1154 snprintf(name, sizeof(name), "S%d", i);
1155 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1156 umap = isl_union_map_add_map(umap, map);
1159 injective = isl_union_map_plain_is_injective(umap);
1161 isl_union_map_free(umap);
1163 return injective;
1168 * cloog_scattering_lazy_block function:
1169 * This function returns 1 if the two scattering functions s1 and s2 given
1170 * as input are the same (except possibly for the final dimension, where we
1171 * allow a difference of 1), assuming that the domains on which this
1172 * scatterings are applied are the same.
1173 * In fact this function answers the question "can I
1174 * safely consider the two domains as only one with two statements (a block) ?".
1175 * A difference of 1 in the final dimension is only allowed if the
1176 * entire scattering function is injective.
1177 * - s1 and s2 are the two domains to check for blocking,
1178 * - scattering is the linked list of all domains,
1179 * - scattdims is the total number of scattering dimentions.
1181 int cloog_scattering_lazy_block(CloogScattering *s1, CloogScattering *s2,
1182 CloogScatteringList *scattering, int scattdims)
1184 int i;
1185 struct isl_dim *dim;
1186 struct isl_map *rel;
1187 struct isl_set *delta;
1188 isl_map *map1 = isl_map_from_cloog_scattering(s1);
1189 isl_map *map2 = isl_map_from_cloog_scattering(s2);
1190 int fixed, block;
1191 isl_int cst;
1192 unsigned n_scat;
1194 n_scat = isl_map_dim(map1, isl_dim_out);
1195 if (n_scat != isl_map_dim(map2, isl_dim_out))
1196 return 0;
1198 dim = isl_map_get_dim(map1);
1199 dim = isl_dim_map_from_set(isl_dim_domain(dim));
1200 rel = isl_map_identity(dim);
1201 rel = isl_map_apply_domain(rel, isl_map_copy(map1));
1202 rel = isl_map_apply_range(rel, isl_map_copy(map2));
1203 delta = isl_map_deltas(rel);
1204 isl_int_init(cst);
1205 for (i = 0; i < n_scat; ++i) {
1206 fixed = isl_set_fast_dim_is_fixed(delta, i, &cst);
1207 if (fixed != 1)
1208 break;
1209 if (isl_int_is_zero(cst))
1210 continue;
1211 if (i + 1 < n_scat)
1212 break;
1213 if (!isl_int_is_one(cst))
1214 break;
1215 if (!injective_scattering(scattering))
1216 break;
1218 block = i >= n_scat;
1219 isl_int_clear(cst);
1220 isl_set_free(delta);
1221 return block;
1226 * cloog_domain_lazy_disjoint function:
1227 * This function returns 1 if the domains given as input are disjoint, 0 if it
1228 * is unable to decide.
1230 int cloog_domain_lazy_disjoint(CloogDomain *d1, CloogDomain *d2)
1232 isl_set *set1 = isl_set_from_cloog_domain(d1);
1233 isl_set *set2 = isl_set_from_cloog_domain(d2);
1234 return isl_set_fast_is_disjoint(set1, set2);
1239 * cloog_scattering_list_lazy_same function:
1240 * This function returns 1 if two domains in the list are the same, 0 if it
1241 * is unable to decide.
1243 int cloog_scattering_list_lazy_same(CloogScatteringList *list)
1245 CloogScatteringList *one, *other;
1246 isl_map *one_map, *other_map;
1248 for (one = list; one; one = one->next) {
1249 one_map = isl_map_from_cloog_scattering(one->scatt);
1250 for (other = one->next; other; other = other->next) {
1251 other_map = isl_map_from_cloog_scattering(other->scatt);
1252 if (isl_map_fast_is_equal(one_map, other_map))
1253 return 1;
1256 return 0;
1259 int cloog_domain_dimension(CloogDomain * domain)
1261 isl_set *set = isl_set_from_cloog_domain(domain);
1262 return isl_set_dim(set, isl_dim_set);
1265 int cloog_domain_parameter_dimension(CloogDomain *domain)
1267 isl_set *set = isl_set_from_cloog_domain(domain);
1268 return isl_set_dim(set, isl_dim_param);
1271 int cloog_scattering_dimension(CloogScattering *scatt, CloogDomain *domain)
1273 isl_map *map = isl_map_from_cloog_scattering(scatt);
1274 return isl_map_dim(map, isl_dim_out);
1277 int cloog_domain_isconvex(CloogDomain * domain)
1279 isl_set *set = isl_set_from_cloog_domain(domain);
1280 return isl_set_n_basic_set(set) <= 1;
1285 * cloog_domain_cut_first function:
1286 * This function splits off and returns the first convex set in the
1287 * union "domain". The remainder of the union is returned in rest.
1288 * The original "domain" itself is destroyed and may not be used
1289 * after a call to this function.
1291 CloogDomain *cloog_domain_cut_first(CloogDomain *domain, CloogDomain **rest)
1293 isl_set *set = isl_set_from_cloog_domain(domain);
1294 struct isl_basic_set *first;
1296 first = isl_set_copy_basic_set(set);
1297 set = isl_set_drop_basic_set(set, first);
1298 *rest = cloog_domain_from_isl_set(set);
1300 return cloog_domain_from_isl_set(isl_set_from_basic_set(first));
1305 * Given a union domain, try to find a simpler representation
1306 * using fewer sets in the union.
1307 * The original "domain" itself is destroyed and may not be used
1308 * after a call to this function.
1310 CloogDomain *cloog_domain_simplify_union(CloogDomain *domain)
1312 isl_set *set = isl_set_from_cloog_domain(domain);
1313 return cloog_domain_from_isl_set(isl_set_coalesce(set));
1318 * cloog_scattering_lazy_isscalar function:
1319 * this function returns 1 if the scattering dimension 'dimension' in the
1320 * scattering 'scatt' is constant.
1321 * If value is not NULL, then it is set to the constant value of dimension.
1323 int cloog_scattering_lazy_isscalar(CloogScattering *scatt, int dimension,
1324 cloog_int_t *value)
1326 isl_map *map = isl_map_from_cloog_scattering(scatt);
1327 return isl_map_fast_is_fixed(map, isl_dim_out, dimension, value);
1332 * cloog_domain_lazy_isconstant function:
1333 * this function returns 1 if the dimension 'dimension' in the
1334 * domain 'domain' is constant.
1335 * If value is not NULL, then it is set to the constant value of dimension.
1337 int cloog_domain_lazy_isconstant(CloogDomain *domain, int dimension,
1338 cloog_int_t *value)
1340 isl_set *set = isl_set_from_cloog_domain(domain);
1341 return isl_set_fast_dim_is_fixed(set, dimension, value);
1346 * cloog_scattering_erase_dimension function:
1347 * this function returns a CloogDomain structure builds from 'domain' where
1348 * we removed the dimension 'dimension' and every constraint involving this
1349 * dimension.
1351 CloogScattering *cloog_scattering_erase_dimension(CloogScattering *scattering,
1352 int dimension)
1354 isl_map *map = isl_map_from_cloog_scattering(scattering);
1355 map = isl_map_remove_dims(isl_map_copy(map), isl_dim_out, dimension, 1);
1356 return cloog_scattering_from_isl_map(map);
1360 * cloog_domain_cube:
1361 * Construct and return a dim-dimensional cube, with values ranging
1362 * between min and max in each dimension.
1364 CloogDomain *cloog_domain_cube(CloogState *state,
1365 int dim, cloog_int_t min, cloog_int_t max)
1367 int i;
1368 struct isl_basic_set *cube;
1369 struct isl_basic_set *interval;
1370 struct isl_basic_set_list *list;
1372 if (dim == 0)
1373 return cloog_domain_universe(state, dim);
1375 interval = isl_basic_set_interval(state->backend->ctx, min, max);
1376 list = isl_basic_set_list_alloc(state->backend->ctx, dim);
1377 for (i = 0; i < dim; ++i)
1378 list = isl_basic_set_list_add(list, isl_basic_set_copy(interval));
1379 isl_basic_set_free(interval);
1380 cube = isl_basic_set_list_product(list);
1381 return cloog_domain_from_isl_set(isl_set_from_basic_set(cube));
1386 * cloog_domain_scatter function:
1387 * This function add the scattering (scheduling) informations to a domain.
1389 CloogDomain *cloog_domain_scatter(CloogDomain *domain, CloogScattering *scatt)
1391 isl_set *set = isl_set_from_cloog_domain(domain);
1392 isl_map *map = isl_map_from_cloog_scattering(scatt);
1394 map = isl_map_reverse(isl_map_copy(map));
1395 map = isl_map_intersect_range(map, set);
1396 set = isl_set_flatten(isl_map_wrap(map));
1397 return cloog_domain_from_isl_set(set);
1400 static int add_domain_from_map(__isl_take isl_map *map, void *user)
1402 isl_dim *dim;
1403 const char *name;
1404 CloogDomain *domain;
1405 CloogScattering *scat;
1406 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1408 dim = isl_map_get_dim(map);
1409 name = isl_dim_get_tuple_name(dim, isl_dim_in);
1410 domain = cloog_domain_from_isl_set(isl_map_domain(isl_map_copy(map)));
1411 scat = cloog_scattering_from_isl_map(map);
1412 *ud = cloog_union_domain_add_domain(*ud, name, domain, scat, NULL);
1413 isl_dim_free(dim);
1415 return 0;
1419 * Construct a CloogUnionDomain from an isl_union_map representing
1420 * a global scattering function. The input is a mapping from different
1421 * spaces (different tuple names and possibly different dimensions)
1422 * to a common space. The iteration domains are set to the domains
1423 * in each space. The statement names are set to the names of the
1424 * spaces. The parameter names of the result are set to those of
1425 * the input, but the iterator and scattering dimension names are
1426 * left unspecified.
1428 CloogUnionDomain *cloog_union_domain_from_isl_union_map(
1429 __isl_take isl_union_map *umap)
1431 int i;
1432 int nparam;
1433 isl_dim *dim;
1434 CloogUnionDomain *ud;
1436 dim = isl_union_map_get_dim(umap);
1437 nparam = isl_dim_size(dim, isl_dim_param);
1439 ud = cloog_union_domain_alloc(nparam);
1441 for (i = 0; i < nparam; ++i) {
1442 const char *s = isl_dim_get_name(dim, isl_dim_param, i);
1443 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1445 isl_dim_free(dim);
1447 if (isl_union_map_foreach_map(umap, &add_domain_from_map, &ud) < 0) {
1448 isl_union_map_free(umap);
1449 cloog_union_domain_free(ud);
1450 assert(0);
1453 isl_union_map_free(umap);
1455 return ud;
1458 static int count_same_name(__isl_keep isl_dim *dim,
1459 enum isl_dim_type type, unsigned pos, const char *name)
1461 enum isl_dim_type t;
1462 unsigned p, s;
1463 int count = 0;
1464 int len = strlen(name);
1466 for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) {
1467 s = t == type ? pos : isl_dim_size(dim, t);
1468 for (p = 0; p < s; ++p) {
1469 const char *n = isl_dim_get_name(dim, t, p);
1470 if (n && !strncmp(n, name, len))
1471 count++;
1474 return count;
1477 static int add_domain(__isl_take isl_set *set, void *user)
1479 int i, nvar;
1480 isl_ctx *ctx;
1481 isl_dim *dim;
1482 char buffer[20];
1483 const char *name;
1484 CloogDomain *domain;
1485 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1487 ctx = isl_set_get_ctx(set);
1488 dim = isl_set_get_dim(set);
1489 name = isl_dim_get_tuple_name(dim, isl_dim_set);
1490 set = isl_set_flatten(set);
1491 set = isl_set_set_tuple_name(set, NULL);
1492 domain = cloog_domain_from_isl_set(set);
1493 *ud = cloog_union_domain_add_domain(*ud, name, domain, NULL, NULL);
1495 nvar = isl_dim_size(dim, isl_dim_set);
1496 for (i = 0; i < nvar; ++i) {
1497 char *long_name = NULL;
1498 int n;
1500 name = isl_dim_get_name(dim, isl_dim_set, i);
1501 if (!name) {
1502 snprintf(buffer, sizeof(buffer), "i%d", i);
1503 name = buffer;
1505 n = count_same_name(dim, isl_dim_set, i, name);
1506 if (n) {
1507 int size = strlen(name) + 10;
1508 long_name = isl_alloc_array(ctx, char, size);
1509 if (!long_name)
1510 cloog_die("memory overflow.\n");
1511 snprintf(long_name, size, "%s_%d", name, n);
1512 name = long_name;
1514 *ud = cloog_union_domain_set_name(*ud, CLOOG_ITER, i, name);
1515 free(long_name);
1517 isl_dim_free(dim);
1519 return 0;
1523 * Construct a CloogUnionDomain from an isl_union_set.
1524 * The statement names are set to the names of the
1525 * spaces. The parameter and iterator names of the result are set to those of
1526 * the input, but the scattering dimension names are left unspecified.
1528 CloogUnionDomain *cloog_union_domain_from_isl_union_set(
1529 __isl_take isl_union_set *uset)
1531 int i;
1532 int nparam;
1533 isl_dim *dim;
1534 CloogUnionDomain *ud;
1536 dim = isl_union_set_get_dim(uset);
1537 nparam = isl_dim_size(dim, isl_dim_param);
1539 ud = cloog_union_domain_alloc(nparam);
1541 for (i = 0; i < nparam; ++i) {
1542 const char *s = isl_dim_get_name(dim, isl_dim_param, i);
1543 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1545 isl_dim_free(dim);
1547 if (isl_union_set_foreach_set(uset, &add_domain, &ud) < 0) {
1548 isl_union_set_free(uset);
1549 cloog_union_domain_free(ud);
1550 assert(0);
1553 isl_union_set_free(uset);
1555 return ud;
1558 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
1559 static void Euclid(cloog_int_t a, cloog_int_t b,
1560 cloog_int_t *x, cloog_int_t *y, cloog_int_t *g)
1562 cloog_int_t c, d, e, f, tmp;
1564 cloog_int_init(c);
1565 cloog_int_init(d);
1566 cloog_int_init(e);
1567 cloog_int_init(f);
1568 cloog_int_init(tmp);
1569 cloog_int_abs(c, a);
1570 cloog_int_abs(d, b);
1571 cloog_int_set_si(e, 1);
1572 cloog_int_set_si(f, 0);
1573 while (cloog_int_is_pos(d)) {
1574 cloog_int_tdiv_q(tmp, c, d);
1575 cloog_int_mul(tmp, tmp, f);
1576 cloog_int_sub(e, e, tmp);
1577 cloog_int_tdiv_q(tmp, c, d);
1578 cloog_int_mul(tmp, tmp, d);
1579 cloog_int_sub(c, c, tmp);
1580 cloog_int_swap(c, d);
1581 cloog_int_swap(e, f);
1583 cloog_int_set(*g, c);
1584 if (cloog_int_is_zero(a))
1585 cloog_int_set_si(*x, 0);
1586 else if (cloog_int_is_pos(a))
1587 cloog_int_set(*x, e);
1588 else cloog_int_neg(*x, e);
1589 if (cloog_int_is_zero(b))
1590 cloog_int_set_si(*y, 0);
1591 else {
1592 cloog_int_mul(tmp, a, *x);
1593 cloog_int_sub(tmp, c, tmp);
1594 cloog_int_divexact(*y, tmp, b);
1596 cloog_int_clear(c);
1597 cloog_int_clear(d);
1598 cloog_int_clear(e);
1599 cloog_int_clear(f);
1600 cloog_int_clear(tmp);
1603 /* Construct a CloogStride from the given constraint for the given level,
1604 * if possible.
1605 * We first compute the gcd of the coefficients of the existentially
1606 * quantified variables and then remove any common factors it has
1607 * with the coefficient at the given level.
1608 * The result is the value of the stride and if it is not one,
1609 * then it is possible to construct a CloogStride.
1610 * The constraint leading to the stride is stored in the CloogStride
1611 * as well a value (factor) such that the product of this value
1612 * and the coefficient at the given level is equal to -1 modulo the stride.
1614 static CloogStride *construct_stride(isl_constraint *c, int level)
1616 int i, n, sign;
1617 isl_int v, m, gcd, stride, factor;
1618 CloogStride *s;
1620 if (!c)
1621 return NULL;
1623 isl_int_init(v);
1624 isl_int_init(m);
1625 isl_int_init(gcd);
1626 isl_int_init(factor);
1627 isl_int_init(stride);
1629 isl_constraint_get_coefficient(c, isl_dim_set, level - 1, &v);
1630 sign = isl_int_sgn(v);
1631 isl_int_abs(m, v);
1633 isl_int_set_si(gcd, 0);
1634 n = isl_constraint_dim(c, isl_dim_div);
1635 for (i = 0; i < n; ++i) {
1636 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
1637 isl_int_gcd(gcd, gcd, v);
1640 isl_int_gcd(v, m, gcd);
1641 isl_int_divexact(stride, gcd, v);
1643 if (isl_int_is_zero(stride) || isl_int_is_one(stride))
1644 s = NULL;
1645 else {
1646 Euclid(m, stride, &factor, &v, &gcd);
1647 if (sign > 0)
1648 isl_int_neg(factor, factor);
1650 c = isl_constraint_copy(c);
1651 s = cloog_stride_alloc_from_constraint(stride,
1652 cloog_constraint_from_isl_constraint(c), factor);
1655 isl_int_clear(stride);
1656 isl_int_clear(factor);
1657 isl_int_clear(gcd);
1658 isl_int_clear(m);
1659 isl_int_clear(v);
1661 return s;
1664 struct cloog_isl_find_stride_data {
1665 int level;
1666 CloogStride *stride;
1669 /* Check if the given constraint can be used to derive
1670 * a stride on the iterator identified by data->level.
1671 * We first check that there are some existentially quantified variables
1672 * and that the coefficient at data->level is non-zero.
1673 * Then we call construct_stride for further checks and the actual
1674 * construction of the CloogStride.
1676 static int find_stride(__isl_take isl_constraint *c, void *user)
1678 struct cloog_isl_find_stride_data *data;
1679 int n;
1680 isl_int v;
1682 data = (struct cloog_isl_find_stride_data *)user;
1684 if (data->stride) {
1685 isl_constraint_free(c);
1686 return 0;
1689 n = isl_constraint_dim(c, isl_dim_div);
1690 if (n == 0) {
1691 isl_constraint_free(c);
1692 return 0;
1695 isl_int_init(v);
1697 isl_constraint_get_coefficient(c, isl_dim_set, data->level - 1, &v);
1698 if (!isl_int_is_zero(v))
1699 data->stride = construct_stride(c, data->level);
1701 isl_int_clear(v);
1703 isl_constraint_free(c);
1705 return 0;
1708 /* Check if the given list of domains has a common stride on the given level.
1709 * If so, return a pointer to a CloogStride object. If not, return NULL.
1711 * We project out all later variables, take the union and compute
1712 * the affine hull of the union. Then we check the (equality)
1713 * constraints in this affine hull for imposing a stride.
1715 CloogStride *cloog_domain_list_stride(CloogDomainList *list, int level)
1717 struct cloog_isl_find_stride_data data = { level, NULL };
1718 isl_set *set;
1719 isl_basic_set *aff;
1720 int first = level;
1721 int n;
1722 int r;
1724 set = isl_set_from_cloog_domain(list->domain);
1725 n = isl_set_dim(set, isl_dim_set) - first;
1726 set = isl_set_project_out(isl_set_copy(set), isl_dim_set, first, n);
1728 for (list = list->next; list; list = list->next) {
1729 isl_set *set_i = isl_set_from_cloog_domain(list->domain);
1730 n = isl_set_dim(set_i, isl_dim_set) - first;
1731 set_i = isl_set_project_out(isl_set_copy(set_i),
1732 isl_dim_set, first, n);
1733 set = isl_set_union(set, set_i);
1735 aff = isl_set_affine_hull(set);
1737 r = isl_basic_set_foreach_constraint(aff, &find_stride, &data);
1738 assert(r == 0);
1740 isl_basic_set_free(aff);
1742 return data.stride;
1745 struct cloog_can_unroll {
1746 int can_unroll;
1747 int level;
1748 isl_constraint *c;
1749 isl_set *set;
1750 isl_int *n;
1755 * Check if the given lower bound can be used for unrolling.
1756 * If the lower bound involves any existentially quantified
1757 * variables, we currently punt.
1758 * Otherwise we compute the maximal value of (i - ceil(l) + 1),
1759 * with l the given lower bound and i the iterator identified by level.
1761 static int is_valid_unrolling_lower_bound(struct cloog_can_unroll *ccu,
1762 __isl_keep isl_constraint *c)
1764 unsigned n_div;
1765 isl_aff *aff;
1766 enum isl_lp_result res;
1768 n_div = isl_constraint_dim(c, isl_dim_div);
1769 if (isl_constraint_involves_dims(c, isl_dim_div, 0, n_div))
1770 return 0;
1772 aff = isl_constraint_get_bound(c, isl_dim_set, ccu->level - 1);
1773 aff = isl_aff_ceil(aff);
1774 aff = isl_aff_neg(aff);
1775 aff = isl_aff_add_coefficient_si(aff, isl_dim_set, ccu->level - 1, 1);
1776 res = isl_set_max(ccu->set, aff, ccu->n);
1777 isl_aff_free(aff);
1779 if (res == isl_lp_unbounded)
1780 return 0;
1782 assert(res == isl_lp_ok);
1784 cloog_int_add_ui(*ccu->n, *ccu->n, 1);
1786 return 1;
1790 /* Check if we can unroll based on the given constraint.
1791 * Only lower bounds can be used.
1792 * Record it if it turns out to be usable and if we haven't recorded
1793 * any other constraint already.
1795 static int constraint_can_unroll(__isl_take isl_constraint *c, void *user)
1797 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1798 isl_int v;
1800 isl_int_init(v);
1801 isl_constraint_get_coefficient(c, isl_dim_set, ccu->level - 1, &v);
1802 if (isl_int_is_pos(v)) {
1803 if (!ccu->c && is_valid_unrolling_lower_bound(ccu, c))
1804 ccu->c = isl_constraint_copy(c);
1806 isl_int_clear(v);
1807 isl_constraint_free(c);
1809 return 0;
1813 /* Check if we can unroll the domain at the current level.
1814 * If the domain is a union, we cannot. Otherwise, we check the
1815 * constraints.
1817 static int basic_set_can_unroll(__isl_take isl_basic_set *bset, void *user)
1819 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1820 int r = 0;
1822 if (ccu->c || !ccu->can_unroll)
1823 ccu->can_unroll = 0;
1824 else {
1825 bset = isl_basic_set_remove_redundancies(bset);
1826 r = isl_basic_set_foreach_constraint(bset,
1827 &constraint_can_unroll, ccu);
1829 isl_basic_set_free(bset);
1830 return r;
1834 /* Check if we can unroll the given domain at the given level, and
1835 * if so, return the single lower bound in *lb and an upper bound
1836 * on the number of iterations in *n.
1837 * If we cannot unroll, return 0 and set *lb to NULL.
1839 * We can unroll, if we can identify a lower bound on level
1840 * such that the number of iterations is bounded by a constant.
1842 int cloog_domain_can_unroll(CloogDomain *domain, int level, cloog_int_t *n,
1843 CloogConstraint **lb)
1845 isl_set *set = isl_set_from_cloog_domain(domain);
1846 struct cloog_can_unroll ccu = { 1, level, NULL, set, n };
1847 int r;
1849 *lb = NULL;
1850 r = isl_set_foreach_basic_set(set, &basic_set_can_unroll, &ccu);
1851 assert(r == 0);
1852 if (!ccu.c)
1853 ccu.can_unroll = 0;
1854 if (!ccu.can_unroll) {
1855 isl_constraint_free(ccu.c);
1856 return 0;
1859 *lb = cloog_constraint_from_isl_constraint(ccu.c);
1861 return ccu.can_unroll;
1865 /* Fix the iterator i at the given level to l + o,
1866 * where l is prescribed by the constraint lb and o is equal to offset.
1867 * In particular, if lb is the constraint
1869 * a i >= f(j)
1871 * then l = ceil(f(j)/a).
1873 CloogDomain *cloog_domain_fixed_offset(CloogDomain *domain,
1874 int level, CloogConstraint *lb, cloog_int_t offset)
1876 isl_aff *aff;
1877 isl_set *set = isl_set_from_cloog_domain(domain);
1878 isl_constraint *c;
1879 isl_constraint *eq;
1881 c = cloog_constraint_to_isl(lb);
1882 aff = isl_constraint_get_bound(c, isl_dim_set, level - 1);
1883 aff = isl_aff_ceil(aff);
1884 aff = isl_aff_add_coefficient_si(aff, isl_dim_set, level - 1, -1);
1885 aff = isl_aff_add_constant(aff, offset);
1886 eq = isl_equality_from_aff(aff);
1887 set = isl_set_add_constraint(set, eq);
1889 return cloog_domain_from_isl_set(set);