add cloog_union_domain_from_isl_union_set
[cloog.git] / source / isl / domain.c
blob294dae23a2cb0af8b91f4f1f15dee291f9a8ec5a
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>
11 CloogDomain *cloog_domain_from_isl_set(struct isl_set *set)
13 set = isl_set_detect_equalities(set);
14 return (CloogDomain *)set;
17 CloogScattering *cloog_scattering_from_isl_map(struct isl_map *map)
19 return (CloogScattering *)map;
23 /**
24 * Returns true if each scattering dimension is defined in terms
25 * of the original iterators.
27 int cloog_scattering_fully_specified(CloogScattering *scattering,
28 CloogDomain *domain)
30 return isl_map_is_single_valued(&scattering->map);
34 CloogConstraintSet *cloog_domain_constraints(CloogDomain *domain)
36 assert(domain->set.n == 1);
37 return cloog_constraint_set_from_isl_basic_set(
38 isl_basic_set_copy(domain->set.p[0]));
42 void cloog_domain_print_constraints(FILE *foo, CloogDomain *domain,
43 int print_number)
45 if (print_number)
46 isl_set_print(&domain->set, foo, 0, ISL_FORMAT_POLYLIB);
47 else {
48 assert(domain->set.n == 1);
49 isl_basic_set_print(domain->set.p[0], foo,
50 0, NULL, NULL, ISL_FORMAT_POLYLIB);
55 void cloog_scattering_print_constraints(FILE *foo, CloogScattering *scattering,
56 int print_number)
58 if (print_number)
59 isl_map_print(&scattering->map, foo, 0, ISL_FORMAT_POLYLIB);
60 else {
61 assert(scattering->map.n == 1);
62 isl_basic_map_print(scattering->map.p[0], foo,
63 0, NULL, NULL, ISL_FORMAT_POLYLIB);
68 void cloog_domain_free(CloogDomain * domain)
70 isl_set_free(&domain->set);
74 void cloog_scattering_free(CloogScattering *scatt)
76 isl_map_free(&scatt->map);
80 CloogDomain * cloog_domain_copy(CloogDomain * domain)
82 return cloog_domain_from_isl_set(isl_set_copy(&domain->set));
86 /**
87 * cloog_domain_convex function:
88 * Computes the convex hull of domain.
89 */
90 CloogDomain *cloog_domain_convex(CloogDomain *domain)
92 struct isl_set *set = &domain->set;
93 set = isl_set_from_basic_set(isl_set_convex_hull(isl_set_copy(set)));
94 return cloog_domain_from_isl_set(set);
98 /**
99 * cloog_domain_simple_convex:
100 * Given a list (union) of polyhedra, this function returns a "simple"
101 * convex hull of this union. In particular, the constraints of the
102 * the returned polyhedron consist of (parametric) lower and upper
103 * bounds on individual variables and constraints that appear in the
104 * original polyhedra.
106 CloogDomain *cloog_domain_simple_convex(CloogDomain *domain)
108 struct isl_basic_set *hull;
109 unsigned dim = isl_set_n_dim(&domain->set);
111 if (cloog_domain_isconvex(domain))
112 return cloog_domain_copy(domain);
114 if (dim == 0)
115 return cloog_domain_convex(domain);
117 hull = isl_set_bounded_simple_hull(isl_set_copy(&domain->set));
118 return cloog_domain_from_isl_set(isl_set_from_basic_set(hull));
123 * cloog_domain_simplify function:
124 * Given two polyhedral domains (dom1) and (dom2),
125 * this function finds the largest domain set (or the smallest list
126 * of non-redundant constraints), that when intersected with polyhedral
127 * domain (dom2) equals (dom1)intersect(dom2). The output is a new CloogDomain
128 * structure with a polyhedral domain with the "redundant" constraints removed.
129 * NB: the second domain is required not to be a union.
131 CloogDomain *cloog_domain_simplify(CloogDomain *dom1, CloogDomain *dom2)
133 struct isl_set *set;
134 set = isl_set_gist(isl_set_copy(&dom1->set), isl_set_copy(&dom2->set));
135 return cloog_domain_from_isl_set(set);
140 * cloog_domain_union function:
141 * This function returns a new polyhedral domain which is the union of
142 * two polyhedral domains (dom1) U (dom2).
143 * Frees dom1 and dom2;
145 CloogDomain *cloog_domain_union(CloogDomain *dom1, CloogDomain *dom2)
147 struct isl_set *set;
148 set = isl_set_union(&dom1->set, &dom2->set);
149 return cloog_domain_from_isl_set(set);
155 * cloog_domain_intersection function:
156 * This function returns a new polyhedral domain which is the intersection of
157 * two polyhedral domains (dom1) \cap (dom2).
159 CloogDomain *cloog_domain_intersection(CloogDomain *dom1, CloogDomain *dom2)
161 struct isl_set *set;
162 set = isl_set_intersect(isl_set_copy(&dom1->set),
163 isl_set_copy(&dom2->set));
164 return cloog_domain_from_isl_set(set);
169 * cloog_domain_difference function:
170 * Returns the set difference domain \ minus.
172 CloogDomain *cloog_domain_difference(CloogDomain *domain, CloogDomain *minus)
174 struct isl_set *set;
175 set = isl_set_subtract(isl_set_copy(&domain->set),
176 isl_set_copy(&minus->set));
177 return cloog_domain_from_isl_set(set);
182 * cloog_domain_sort function:
183 * This function topologically sorts (nb_doms) domains. Here (doms) is an
184 * array of pointers to CloogDomains, (nb_doms) is the number of domains,
185 * (level) is the level to consider for partial ordering (nb_par) is the
186 * parameter space dimension, (permut) if not NULL, is an array of (nb_doms)
187 * integers that contains a permutation specification after call in order to
188 * apply the topological sorting.
190 void cloog_domain_sort(CloogDomain **doms, unsigned nb_doms, unsigned level,
191 int *permut)
193 int i, j, k, cmp;
194 struct isl_ctx *ctx;
195 unsigned char **follows;
197 if (!nb_doms)
198 return;
199 ctx = doms[0]->set.ctx;
200 for (i = 0; i < nb_doms; i++)
201 assert(doms[i]->set.n == 1);
203 follows = isl_alloc_array(ctx, unsigned char *, nb_doms);
204 assert(follows);
205 for (i = 0; i < nb_doms; ++i) {
206 follows[i] = isl_alloc_array(ctx, unsigned char, nb_doms);
207 assert(follows[i]);
208 for (j = 0; j < nb_doms; ++j)
209 follows[i][j] = 0;
212 for (i = 1; i < nb_doms; ++i) {
213 for (j = 0; j < i; ++j) {
214 if (follows[i][j] || follows[j][i])
215 continue;
216 cmp = isl_basic_set_compare_at(doms[i]->set.p[0],
217 doms[j]->set.p[0], level-1);
218 if (!cmp)
219 continue;
220 if (cmp > 0) {
221 follows[i][j] = 1;
222 for (k = 0; k < i; ++k)
223 follows[i][k] |= follows[j][k];
224 } else {
225 follows[j][i] = 1;
226 for (k = 0; k < i; ++k)
227 follows[k][i] |= follows[k][j];
232 for (i = 0, j = 0; i < nb_doms; j = (j + 1) % nb_doms) {
233 for (k = 0; k < nb_doms; ++k)
234 if (follows[j][k])
235 break;
236 if (k < nb_doms)
237 continue;
238 for (k = 0; k < nb_doms; ++k)
239 follows[k][j] = 0;
240 follows[j][j] = 1;
241 permut[i] = 1 + j;
242 ++i;
245 for (i = 0; i < nb_doms; ++i)
246 free(follows[i]);
247 free(follows);
252 * Check whether there is or may be any value of dom1 at the given level
253 * that is greater than or equal to a value of dom2 at the same level.
255 * Return
256 * 1 is there is or may be a greater-than pair.
257 * 0 if there is no greater-than pair, but there may be an equal-to pair
258 * -1 if there is definitely no such pair
260 int cloog_domain_follows(CloogDomain *dom1, CloogDomain *dom2, unsigned level)
262 int follows;
264 follows = isl_set_follows_at(&dom1->set, &dom2->set, level - 1);
265 assert(follows >= -1);
267 return follows;
272 * cloog_domain_empty function:
273 * Returns an empty domain of the same dimensions as template.
275 CloogDomain *cloog_domain_empty(CloogDomain *template)
277 return cloog_domain_from_isl_set(isl_set_empty_like(&template->set));
282 * Return 1 if the specified dimension has both an upper and a lower bound.
284 int cloog_domain_is_bounded(CloogDomain *dom, unsigned level)
286 return isl_set_dim_is_bounded(&dom->set, isl_dim_set, level - 1);
290 /******************************************************************************
291 * Structure display function *
292 ******************************************************************************/
296 * cloog_domain_print_structure :
297 * this function is a more human-friendly way to display the CloogDomain data
298 * structure, it only shows the constraint system and includes an indentation
299 * level (level) in order to work with others print_structure functions.
301 void cloog_domain_print_structure(FILE *file, CloogDomain *domain, int level,
302 const char *name)
304 int i ;
305 char *suffix = " ]";
306 char *prefix;
307 struct isl_set *set = &domain->set;
309 /* Go to the right level. */
310 for (i = 0; i < level; i++)
311 fprintf(file, "|\t");
313 if (!set) {
314 fprintf(file, "+-- Null CloogDomain\n");
315 return;
317 fprintf(file, "+-- %s\n", name);
318 prefix = isl_alloc_array(set->ctx, char, 2*(level+1)+3);
319 assert(prefix);
320 for (i = 0; i < level+1; ++i)
321 memcpy(prefix+2*i, "|\t", 2);
322 strcpy(prefix+2*(level+1), "[ ");
324 for (i = 0; i < set->n; ++i) {
325 isl_basic_set_print(set->p[i], file, 0, prefix, suffix,
326 ISL_FORMAT_POLYLIB_CONSTRAINTS);
327 prefix[2*(level+1)] = '\0';
328 fprintf(file, "%s\n", prefix);
329 prefix[2*(level+1)] = '[';
331 free(prefix);
335 /******************************************************************************
336 * Memory deallocation function *
337 ******************************************************************************/
341 * cloog_scattering_list_free function:
342 * This function frees the allocated memory for a CloogScatteringList structure.
344 void cloog_scattering_list_free(CloogScatteringList *list)
346 while (list != NULL) {
347 CloogScatteringList *temp = list->next;
348 isl_map_free(&list->scatt->map);
349 free(list);
350 list = temp;
355 /******************************************************************************
356 * Reading function *
357 ******************************************************************************/
361 * cloog_domain_read_context function:
362 * Read parameter domain.
364 CloogDomain *cloog_domain_read_context(CloogState *state, FILE *input)
366 struct isl_ctx *ctx = state->backend->ctx;
367 isl_set *set;
369 set = isl_set_read_from_file(ctx, input, 0);
370 set = isl_set_move_dims(set, isl_dim_param, 0,
371 isl_dim_set, 0, isl_set_dim(set, isl_dim_set));
373 return cloog_domain_from_isl_set(set);
378 * cloog_domain_from_context
379 * Reinterpret context by turning parameters into variables.
381 CloogDomain *cloog_domain_from_context(CloogDomain *context)
383 isl_set *set = &context->set;
385 set = isl_set_move_dims(set, isl_dim_set, 0,
386 isl_dim_param, 0, isl_set_dim(set, isl_dim_param));
388 return cloog_domain_from_isl_set(set);
393 * cloog_domain_union_read function:
394 * This function reads a union of polyhedra into a file (input) and
395 * returns a pointer to a CloogDomain containing the read information.
397 CloogDomain *cloog_domain_union_read(CloogState *state,
398 FILE *input, int nb_parameters)
400 struct isl_ctx *ctx = state->backend->ctx;
401 struct isl_set *set;
403 set = isl_set_read_from_file(ctx, input, nb_parameters);
404 return cloog_domain_from_isl_set(set);
409 * cloog_domain_read_scattering function:
410 * This function reads in a scattering function from the file input.
412 * We try to read the scattering relation as a map, but if it is
413 * specified in the original PolyLib format, then isl_map_read_from_file
414 * will treat the input as a set return a map with zero input dimensions.
415 * In this case, we need to decompose the set into a map from
416 * scattering dimensions to domain dimensions and then invert the
417 * resulting map.
419 CloogScattering *cloog_domain_read_scattering(CloogDomain *domain, FILE *input)
421 struct isl_ctx *ctx = domain->set.ctx;
422 struct isl_map *scat;
423 unsigned nparam;
424 unsigned dim;
425 unsigned n_scat;
427 dim = isl_set_n_dim(&domain->set);
428 nparam = isl_set_n_param(&domain->set);
429 scat = isl_map_read_from_file(ctx, input, nparam);
430 if (isl_map_dim(scat, isl_dim_in) != dim) {
431 n_scat = isl_map_dim(scat, isl_dim_out) - dim;
432 scat = isl_map_move_dims(scat, isl_dim_in, 0,
433 isl_dim_out, n_scat, dim);
435 return cloog_scattering_from_isl_map(scat);
438 /******************************************************************************
439 * CloogMatrix Reading function *
440 ******************************************************************************/
443 * isl_constraint_read_from_matrix:
444 * Convert a single line of a matrix to a isl_constraint.
445 * Returns a pointer to the constraint if successful; NULL otherwise.
447 static struct isl_constraint *isl_constraint_read_from_matrix(
448 struct isl_dim *dim, cloog_int_t *row)
450 struct isl_constraint *constraint;
451 int j;
452 int nvariables = isl_dim_size(dim, isl_dim_set);
453 int nparam = isl_dim_size(dim, isl_dim_param);
455 if (cloog_int_is_zero(row[0]))
456 constraint = isl_equality_alloc(dim);
457 else
458 constraint = isl_inequality_alloc(dim);
460 for (j = 0; j < nvariables; ++j)
461 isl_constraint_set_coefficient(constraint, isl_dim_out, j,
462 row[1 + j]);
464 for (j = 0; j < nparam; ++j)
465 isl_constraint_set_coefficient(constraint, isl_dim_param, j,
466 row[1 + nvariables + j]);
468 isl_constraint_set_constant(constraint, row[1 + nvariables + nparam]);
470 return constraint;
474 * isl_basic_set_read_from_matrix:
475 * Convert matrix to basic_set. The matrix contains nparam parameter columns.
476 * Returns a pointer to the basic_set if successful; NULL otherwise.
478 static struct isl_basic_set *isl_basic_set_read_from_matrix(struct isl_ctx *ctx,
479 CloogMatrix* matrix, int nparam)
481 struct isl_dim *dim;
482 struct isl_basic_set *bset;
483 int i;
484 unsigned nrows, ncolumns;
486 nrows = matrix->NbRows;
487 ncolumns = matrix->NbColumns;
488 int nvariables = ncolumns - 2 - nparam;
490 dim = isl_dim_set_alloc(ctx, nparam, nvariables);
492 bset = isl_basic_set_universe(isl_dim_copy(dim));
494 for (i = 0; i < nrows; ++i) {
495 cloog_int_t *row = matrix->p[i];
496 struct isl_constraint *constraint =
497 isl_constraint_read_from_matrix(isl_dim_copy(dim), row);
498 bset = isl_basic_set_add_constraint(bset, constraint);
501 isl_dim_free(dim);
503 return bset;
507 * cloog_domain_from_cloog_matrix:
508 * Create a CloogDomain containing the constraints described in matrix.
509 * nparam is the number of parameters contained in the domain.
510 * Returns a pointer to the CloogDomain if successful; NULL otherwise.
512 CloogDomain *cloog_domain_from_cloog_matrix(CloogState *state,
513 CloogMatrix *matrix, int nparam)
515 struct isl_ctx *ctx = state->backend->ctx;
516 struct isl_basic_set *bset;
518 bset = isl_basic_set_read_from_matrix(ctx, matrix, nparam);
520 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
524 * cloog_scattering_from_cloog_matrix:
525 * Create a CloogScattering containing the constraints described in matrix.
526 * nparam is the number of parameters contained in the domain.
527 * Returns a pointer to the CloogScattering if successful; NULL otherwise.
529 CloogScattering *cloog_scattering_from_cloog_matrix(CloogState *state,
530 CloogMatrix *matrix, int nb_scat, int nb_par)
532 struct isl_ctx *ctx = state->backend->ctx;
533 struct isl_basic_set *bset;
534 struct isl_basic_map *scat;
535 struct isl_dim *dims;
536 unsigned dim;
538 bset = isl_basic_set_read_from_matrix(ctx, matrix, nb_par);
539 dim = isl_basic_set_n_dim(bset) - nb_scat;
540 dims = isl_dim_alloc(ctx, nb_par, nb_scat, dim);
542 scat = isl_basic_map_from_basic_set(bset, dims);
543 scat = isl_basic_map_reverse(scat);
544 return cloog_scattering_from_isl_map(isl_map_from_basic_map(scat));
548 /******************************************************************************
549 * Processing functions *
550 ******************************************************************************/
555 * cloog_domain_isempty function:
557 int cloog_domain_isempty(CloogDomain *domain)
559 return isl_set_is_empty(&domain->set);
564 * cloog_domain_universe function:
565 * This function returns the complete dim-dimensional space.
567 CloogDomain *cloog_domain_universe(CloogState *state, unsigned dim)
569 struct isl_dim *dims;
570 struct isl_basic_set *bset;
572 dims = isl_dim_set_alloc(state->backend->ctx, 0, dim);
573 bset = isl_basic_set_universe(dims);
574 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
579 * cloog_domain_project function:
580 * This function returns the projection of
581 * (domain) on the (level) first dimensions (i.e. outer loops).
583 CloogDomain *cloog_domain_project(CloogDomain *domain, int level)
585 struct isl_set *set = &domain->set;
586 set = isl_set_remove_dims(isl_set_copy(set),
587 level, isl_set_n_dim(set) - level);
588 set = isl_set_compute_divs(set);
589 return cloog_domain_from_isl_set(set);
594 * cloog_domain_extend function:
595 * This function returns the (domain) given as input with (dim)
596 * dimensions and (nb_par) parameters.
597 * This function does not free (domain), and returns a new CloogDomain.
599 CloogDomain *cloog_domain_extend(CloogDomain *domain, int dim)
601 struct isl_set *set = &domain->set;
602 set = isl_set_extend(isl_set_copy(set), isl_set_n_param(set), dim);
603 return cloog_domain_from_isl_set(set);
608 * cloog_domain_never_integral function:
609 * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0.
610 * There is no need to check for such constraints explicitly for the isl
611 * backend.
613 int cloog_domain_never_integral(CloogDomain * domain)
615 return isl_set_is_empty(&domain->set);
620 * Check whether the loop at "level" is executed at most once.
621 * We construct a map that maps all remaining variables to this iterator
622 * and check whether this map is single valued.
624 * Alternatively, we could have mapped the domain through a mapping
625 * [p] -> { [..., i] -> [..., i'] : i' > i }
626 * and then taken the intersection of the original domain and the transformed
627 * domain. If this intersection is empty, then the corresponding
628 * loop is executed at most once.
630 int cloog_domain_is_otl(CloogDomain *domain, int level)
632 int otl;
633 isl_map *map;
635 map = isl_map_from_domain(isl_set_copy(&domain->set));
636 map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_in, level - 1, 1);
637 otl = isl_map_is_single_valued(map);
638 isl_map_free(map);
640 return otl;
645 * cloog_domain_stride function:
646 * This function finds the stride imposed to unknown with the column number
647 * 'strided_level' in order to be integral. For instance, if we have a
648 * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral
649 * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to
650 * the unknown i. The function returns the imposed stride in a parameter field.
651 * - domain is the set of constraint we have to consider,
652 * - strided_level is the column number of the unknown for which a stride have
653 * to be found,
654 * - looking_level is the column number of the unknown that impose a stride to
655 * the first unknown.
656 * - stride is the stride that is returned back as a function parameter.
657 * - offset is the value of the constant c if the condition is of the shape
658 * (i + c)%s = 0, s being the stride.
660 void cloog_domain_stride(CloogDomain *domain, int strided_level,
661 cloog_int_t *stride, cloog_int_t *offset)
663 struct isl_set *set = &domain->set;
664 isl_set_dim_residue_class(set, strided_level - 1, stride, offset);
665 if (!isl_int_is_zero(*offset))
666 isl_int_sub(*offset, *stride, *offset);
667 return;
671 struct cloog_can_stride {
672 int level;
673 int can_stride;
676 static int constraint_can_stride(__isl_take isl_constraint *c, void *user)
678 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
679 int i;
680 isl_int v;
681 unsigned n_div;
683 isl_int_init(v);
684 isl_constraint_get_coefficient(c, isl_dim_set, ccs->level - 1, &v);
685 if (isl_int_is_pos(v)) {
686 n_div = isl_constraint_dim(c, isl_dim_div);
687 for (i = 0; i < n_div; ++i) {
688 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
689 if (!isl_int_is_zero(v))
690 break;
692 if (i < n_div)
693 ccs->can_stride = 0;
695 isl_int_clear(v);
696 isl_constraint_free(c);
698 return 0;
701 static int basic_set_can_stride(__isl_take isl_basic_set *bset, void *user)
703 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
704 int r;
706 r = isl_basic_set_foreach_constraint(bset, constraint_can_stride, ccs);
707 isl_basic_set_free(bset);
708 return r;
713 * Return 1 if CLooG is allowed to perform stride detection on level "level"
714 * and 0 otherwise.
715 * Currently, stride detection is only allowed when none of the lower
716 * bound constraints involve any existentially quantified variables.
717 * The reason is that the current isl interface does not make it
718 * easy to construct an integer division that depends on other integer
719 * divisions.
720 * By not allowing existentially quantified variables in the constraints,
721 * we can ignore them in cloog_domain_stride_lower_bound.
723 int cloog_domain_can_stride(CloogDomain *domain, int level)
725 struct cloog_can_stride ccs = { level, 1 };
726 int r;
727 r = isl_set_foreach_basic_set(&domain->set, basic_set_can_stride, &ccs);
728 assert(r == 0);
729 return ccs.can_stride;
733 struct cloog_stride_lower {
734 int level;
735 isl_int stride;
736 isl_int offset;
737 isl_set *set;
738 isl_basic_set *bounds;
741 /* If the given constraint is a lower bound on csl->level, then add
742 * a lower bound to csl->bounds that makes sure that the remainder
743 * of the smallest value on division by csl->stride is equal to csl->offset.
745 * In particular, the given lower bound is of the form
747 * a i + f >= 0
749 * where f may depend on the parameters and other iterators.
750 * The stride is s and the offset is d.
751 * The lower bound -f/a may not satisfy the above condition. In fact,
752 * it may not even be integral. We want to round this value of i up
753 * to the nearest value that satisfies the condition and add the corresponding
754 * lower bound constraint. This nearest value is obtained by rounding
755 * i - d up to the nearest multiple of s.
756 * That is, we first subtract d
758 * i' = -f/a - d
760 * then we round up to the nearest multiple of s
762 * i'' = s * ceil(i'/s)
764 * and finally, we add d again
766 * i''' = i'' + d
768 * and impose the constraint i >= i'''.
770 * We find
772 * i'' = s * ceil((-f - a * d)/(a * s)) = - s * floor((f + a * d)/(a * s))
774 * i >= - s * floor((f + a * d)/(a * s)) + d
776 * or
777 * i + s * floor((f + a * d)/(a * s)) - d >= 0
779 static int constraint_stride_lower(__isl_take isl_constraint *c, void *user)
781 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
782 int i;
783 isl_int v;
784 isl_int t;
785 isl_constraint *bound;
786 isl_div *div;
787 int pos;
788 unsigned nparam, nvar;
790 isl_int_init(v);
791 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
792 if (!isl_int_is_pos(v)) {
793 isl_int_clear(v);
794 isl_constraint_free(c);
796 return 0;
799 isl_int_init(t);
801 nparam = isl_constraint_dim(c, isl_dim_param);
802 nvar = isl_constraint_dim(c, isl_dim_set);
803 bound = isl_inequality_alloc(isl_basic_set_get_dim(csl->bounds));
804 div = isl_div_alloc(isl_basic_set_get_dim(csl->bounds));
805 isl_int_mul(t, v, csl->stride);
806 isl_div_set_denominator(div, t);
807 for (i = 0; i < nparam; ++i) {
808 isl_constraint_get_coefficient(c, isl_dim_param, i, &t);
809 isl_div_set_coefficient(div, isl_dim_param, i, t);
811 for (i = 0; i < nvar; ++i) {
812 if (i == csl->level - 1)
813 continue;
814 isl_constraint_get_coefficient(c, isl_dim_set, i, &t);
815 isl_div_set_coefficient(div, isl_dim_set, i, t);
817 isl_constraint_get_constant(c, &t);
818 isl_int_addmul(t, v, csl->offset);
819 isl_div_set_constant(div, t);
821 bound = isl_constraint_add_div(bound, div, &pos);
822 isl_int_set_si(t, 1);
823 isl_constraint_set_coefficient(bound, isl_dim_set,
824 csl->level - 1, t);
825 isl_constraint_set_coefficient(bound, isl_dim_div, pos,
826 csl->stride);
827 isl_int_neg(t, csl->offset);
828 isl_constraint_set_constant(bound, t);
829 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
831 isl_int_clear(v);
832 isl_int_clear(t);
833 isl_constraint_free(c);
835 return 0;
838 static int basic_set_stride_lower(__isl_take isl_basic_set *bset, void *user)
840 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
841 int r;
843 csl->bounds = isl_basic_set_universe_like(bset);
844 r = isl_basic_set_foreach_constraint(bset, constraint_stride_lower, csl);
845 bset = isl_basic_set_intersect(bset, csl->bounds);
846 csl->set = isl_set_union(csl->set, isl_set_from_basic_set(bset));
848 return r;
852 * Update the lower bounds at level "level" to the given stride information.
853 * That is, make sure that the remainder on division by "stride"
854 * is equal to "offset".
856 CloogDomain *cloog_domain_stride_lower_bound(CloogDomain *domain, int level,
857 cloog_int_t stride, cloog_int_t offset)
859 struct cloog_stride_lower csl;
860 int r;
862 isl_int_init(csl.stride);
863 isl_int_init(csl.offset);
864 csl.level = level;
865 csl.set = isl_set_empty_like(&domain->set);
866 isl_int_set(csl.stride, stride);
867 isl_int_set(csl.offset, offset);
869 r = isl_set_foreach_basic_set(&domain->set, basic_set_stride_lower, &csl);
870 assert(r == 0);
872 isl_int_clear(csl.stride);
873 isl_int_clear(csl.offset);
875 cloog_domain_free(domain);
876 return cloog_domain_from_isl_set(csl.set);
881 * cloog_domain_lazy_equal function:
882 * This function returns 1 if the domains given as input are the same, 0 if it
883 * is unable to decide.
885 int cloog_domain_lazy_equal(CloogDomain *d1, CloogDomain *d2)
887 return isl_set_fast_is_equal(&d1->set, &d2->set);
890 struct cloog_bound_split {
891 isl_set *set;
892 int level;
893 int lower;
894 int upper;
897 static int constraint_bound_split(__isl_take isl_constraint *c, void *user)
899 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
900 isl_int v;
901 int i;
902 int handle = 0;
904 isl_int_init(v);
905 isl_constraint_get_coefficient(c, isl_dim_set, cbs->level - 1, &v);
906 if (!cbs->lower && isl_int_is_pos(v))
907 cbs->lower = handle = 1;
908 else if (!cbs->upper && isl_int_is_neg(v))
909 cbs->upper = handle = 1;
910 if (handle) {
911 for (i = 0; i < isl_set_dim(cbs->set, isl_dim_param); ++i) {
912 isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
913 if (isl_int_is_zero(v))
914 continue;
915 cbs->set = isl_set_split_dims(cbs->set,
916 isl_dim_param, i, 1);
919 isl_int_clear(v);
920 isl_constraint_free(c);
922 return (cbs->lower && cbs->upper) ? -1 : 0;
925 static int basic_set_bound_split(__isl_take isl_basic_set *bset, void *user)
927 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
928 int r;
930 cbs->lower = 0;
931 cbs->upper = 0;
932 r = isl_basic_set_foreach_constraint(bset, constraint_bound_split, cbs);
933 isl_basic_set_free(bset);
934 return ((!cbs->lower || !cbs->upper) && r < 0) ? -1 : 0;
938 * Return a union of sets S_i such that the convex hull of "dom",
939 * when intersected with one the sets S_i, will have an upper and
940 * lower bound for the dimension at "level" (provided "dom" itself
941 * has such bounds for the dimensions).
943 * We currently take a very simple approach. For each of the basic
944 * sets in "dom" we pick a lower and an upper bound and split the
945 * range of any parameter involved in these two bounds in a
946 * nonnegative and a negative part. This ensures that the symbolic
947 * constant in these two constraints are themselves bounded and
948 * so there will be at least one upper and one lower bound
949 * in the convex hull.
951 CloogDomain *cloog_domain_bound_splitter(CloogDomain *dom, int level)
953 struct cloog_bound_split cbs;
954 int r;
955 cbs.level = level;
956 cbs.set = isl_set_universe_like(&dom->set);
957 r = isl_set_foreach_basic_set(&dom->set, basic_set_bound_split, &cbs);
958 assert(r == 0);
959 return cloog_domain_from_isl_set(cbs.set);
964 * cloog_scattering_lazy_block function:
965 * This function returns 1 if the two scattering functions s1 and s2 given
966 * as input are the same (except possibly for the final dimension, where we
967 * allow a difference of 1), assuming that the domains on which this
968 * scatterings are applied are the same.
969 * In fact this function answers the question "can I
970 * safely consider the two domains as only one with two statements (a block) ?".
971 * - s1 and s2 are the two domains to check for blocking,
972 * - scattering is the linked list of all domains,
973 * - scattdims is the total number of scattering dimentions.
975 int cloog_scattering_lazy_block(CloogScattering *s1, CloogScattering *s2,
976 CloogScatteringList *scattering, int scattdims)
978 int i;
979 struct isl_dim *dim;
980 struct isl_map *rel;
981 struct isl_set *delta;
982 int fixed, block;
983 isl_int cst;
984 unsigned n_scat;
986 n_scat = isl_map_dim(&s1->map, isl_dim_out);
987 if (n_scat != isl_map_dim(&s2->map, isl_dim_out))
988 return 0;
990 dim = isl_dim_copy(s1->map.dim);
991 dim = isl_dim_domain(dim);
992 rel = isl_map_identity(dim);
993 rel = isl_map_apply_domain(rel, isl_map_copy(&s1->map));
994 rel = isl_map_apply_range(rel, isl_map_copy(&s2->map));
995 delta = isl_map_deltas(rel);
996 isl_int_init(cst);
997 for (i = 0; i < n_scat; ++i) {
998 fixed = isl_set_fast_dim_is_fixed(delta, i, &cst);
999 if (fixed != 1)
1000 break;
1001 if (i+1 < n_scat && !isl_int_is_zero(cst))
1002 break;
1003 if (!isl_int_is_zero(cst) && !isl_int_is_one(cst))
1004 break;
1006 block = i >= n_scat;
1007 isl_int_clear(cst);
1008 isl_set_free(delta);
1009 return block;
1014 * cloog_domain_lazy_disjoint function:
1015 * This function returns 1 if the domains given as input are disjoint, 0 if it
1016 * is unable to decide.
1018 int cloog_domain_lazy_disjoint(CloogDomain *d1, CloogDomain *d2)
1020 return isl_set_fast_is_disjoint(&d1->set, &d2->set);
1025 * cloog_scattering_list_lazy_same function:
1026 * This function returns 1 if two domains in the list are the same, 0 if it
1027 * is unable to decide.
1029 int cloog_scattering_list_lazy_same(CloogScatteringList *list)
1031 CloogScatteringList *one, *other;
1033 for (one = list; one; one = one->next)
1034 for (other = one->next; other; other = other->next)
1035 if (isl_map_fast_is_equal(&one->scatt->map,
1036 &other->scatt->map))
1037 return 1;
1038 return 0;
1041 int cloog_domain_dimension(CloogDomain * domain)
1043 return isl_set_n_dim(&domain->set);
1046 int cloog_domain_parameter_dimension(CloogDomain *domain)
1048 return isl_set_n_param(&domain->set);
1051 int cloog_scattering_dimension(CloogScattering *scatt, CloogDomain *domain)
1053 return isl_map_dim(&scatt->map, isl_dim_out);
1056 int cloog_domain_isconvex(CloogDomain * domain)
1058 return domain->set.n <= 1;
1063 * cloog_domain_cut_first function:
1064 * This function splits off and returns the first convex set in the
1065 * union "domain". The remainder of the union is returned in rest.
1066 * The original "domain" itself is destroyed and may not be used
1067 * after a call to this function.
1069 CloogDomain *cloog_domain_cut_first(CloogDomain *domain, CloogDomain **rest)
1071 struct isl_set *set;
1072 struct isl_basic_set *first;
1074 set = &domain->set;
1075 first = isl_set_copy_basic_set(set);
1076 set = isl_set_drop_basic_set(set, first);
1077 *rest = cloog_domain_from_isl_set(set);
1079 return cloog_domain_from_isl_set(isl_set_from_basic_set(first));
1084 * Given a union domain, try to find a simpler representation
1085 * using fewer sets in the union.
1086 * The original "domain" itself is destroyed and may not be used
1087 * after a call to this function.
1089 CloogDomain *cloog_domain_simplify_union(CloogDomain *domain)
1091 return cloog_domain_from_isl_set(isl_set_coalesce(&domain->set));
1096 * cloog_scattering_lazy_isscalar function:
1097 * this function returns 1 if the scattering dimension 'dimension' in the
1098 * scattering 'scatt' is constant.
1099 * If value is not NULL, then it is set to the constant value of dimension.
1101 int cloog_scattering_lazy_isscalar(CloogScattering *scatt, int dimension,
1102 cloog_int_t *value)
1104 return isl_map_fast_is_fixed(&scatt->map, isl_dim_out, dimension, value);
1109 * cloog_domain_lazy_isconstant function:
1110 * this function returns 1 if the dimension 'dimension' in the
1111 * domain 'domain' is constant.
1112 * If value is not NULL, then it is set to the constant value of dimension.
1114 int cloog_domain_lazy_isconstant(CloogDomain *domain, int dimension)
1116 return isl_set_fast_dim_is_fixed(&domain->set, dimension, NULL);
1121 * cloog_scattering_erase_dimension function:
1122 * this function returns a CloogDomain structure builds from 'domain' where
1123 * we removed the dimension 'dimension' and every constraint involving this
1124 * dimension.
1126 CloogScattering *cloog_scattering_erase_dimension(CloogScattering *domain,
1127 int dimension)
1129 struct isl_map *map;
1130 map = isl_map_remove(isl_map_copy(&domain->map), isl_dim_out, dimension, 1);
1131 return cloog_scattering_from_isl_map(map);
1135 * cloog_domain_cube:
1136 * Construct and return a dim-dimensional cube, with values ranging
1137 * between min and max in each dimension.
1139 CloogDomain *cloog_domain_cube(CloogState *state,
1140 int dim, cloog_int_t min, cloog_int_t max)
1142 int i;
1143 struct isl_basic_set *cube;
1144 struct isl_basic_set *interval;
1145 struct isl_basic_set_list *list;
1147 if (dim == 0)
1148 return cloog_domain_universe(state, dim);
1150 interval = isl_basic_set_interval(state->backend->ctx, min, max);
1151 list = isl_basic_set_list_alloc(state->backend->ctx, dim);
1152 for (i = 0; i < dim; ++i)
1153 list = isl_basic_set_list_add(list, isl_basic_set_copy(interval));
1154 isl_basic_set_free(interval);
1155 cube = isl_basic_set_product(list);
1156 return cloog_domain_from_isl_set(isl_set_from_basic_set(cube));
1161 * cloog_domain_scatter function:
1162 * This function add the scattering (scheduling) informations to a domain.
1164 CloogDomain *cloog_domain_scatter(CloogDomain *domain, CloogScattering *scatt)
1166 struct isl_map *map;
1168 map = isl_map_reverse(isl_map_copy(&scatt->map));
1169 map = isl_map_intersect_range(map, &domain->set);
1170 return cloog_domain_from_isl_set(isl_set_from_map(map));
1173 static int add_domain_from_map(__isl_take isl_map *map, void *user)
1175 isl_dim *dim;
1176 const char *name;
1177 CloogDomain *domain;
1178 CloogScattering *scat;
1179 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1181 dim = isl_map_get_dim(map);
1182 name = isl_dim_get_tuple_name(dim, isl_dim_in);
1183 domain = cloog_domain_from_isl_set(isl_map_domain(isl_map_copy(map)));
1184 scat = cloog_scattering_from_isl_map(map);
1185 *ud = cloog_union_domain_add_domain(*ud, name, domain, scat, NULL);
1186 isl_dim_free(dim);
1188 return 0;
1192 * Construct a CloogUnionDomain from an isl_union_map representing
1193 * a global scattering function. The input is a mapping from different
1194 * spaces (different tuple names and possibly different dimensions)
1195 * to a common space. The iteration domains are set to the domains
1196 * in each space. The statement names are set to the names of the
1197 * spaces. The parameter names of the result are set to those of
1198 * the input, but the iterator and scattering dimension names are
1199 * left unspecified.
1201 CloogUnionDomain *cloog_union_domain_from_isl_union_map(
1202 __isl_take isl_union_map *umap)
1204 int i;
1205 int nparam;
1206 isl_dim *dim;
1207 CloogUnionDomain *ud;
1209 dim = isl_union_map_get_dim(umap);
1210 nparam = isl_dim_size(dim, isl_dim_param);
1212 ud = cloog_union_domain_alloc(nparam);
1214 for (i = 0; i < nparam; ++i) {
1215 const char *s = isl_dim_get_name(dim, isl_dim_param, i);
1216 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1218 isl_dim_free(dim);
1220 if (isl_union_map_foreach_map(umap, &add_domain_from_map, &ud) < 0) {
1221 isl_union_map_free(umap);
1222 cloog_union_domain_free(ud);
1223 assert(0);
1226 isl_union_map_free(umap);
1228 return ud;
1231 static int add_domain(__isl_take isl_set *set, void *user)
1233 isl_dim *dim;
1234 const char *name;
1235 CloogDomain *domain;
1236 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1238 dim = isl_set_get_dim(set);
1239 name = isl_dim_get_tuple_name(dim, isl_dim_in);
1240 domain = cloog_domain_from_isl_set(set);
1241 *ud = cloog_union_domain_add_domain(*ud, name, domain, NULL, NULL);
1242 isl_dim_free(dim);
1244 return 0;
1248 * Construct a CloogUnionDomain from an isl_union_set.
1249 * The statement names are set to the names of the
1250 * spaces. The parameter names of the result are set to those of
1251 * the input, but the iterator and scattering dimension names are
1252 * left unspecified.
1254 CloogUnionDomain *cloog_union_domain_from_isl_union_set(
1255 __isl_take isl_union_set *uset)
1257 int i;
1258 int nparam;
1259 isl_dim *dim;
1260 CloogUnionDomain *ud;
1262 dim = isl_union_set_get_dim(uset);
1263 nparam = isl_dim_size(dim, isl_dim_param);
1265 ud = cloog_union_domain_alloc(nparam);
1267 for (i = 0; i < nparam; ++i) {
1268 const char *s = isl_dim_get_name(dim, isl_dim_param, i);
1269 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1271 isl_dim_free(dim);
1273 if (isl_union_set_foreach_set(uset, &add_domain, &ud) < 0) {
1274 isl_union_set_free(uset);
1275 cloog_union_domain_free(ud);
1276 assert(0);
1279 isl_union_set_free(uset);
1281 return ud;