cloog_domain_lazy_isconstant: add extra argument to retrieve constant value
[cloog.git] / source / isl / domain.c
blob504b5c98732c2f49bcb7468b82333be371cf1a6b
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 set = isl_set_compute_divs(set);
15 return (CloogDomain *)set;
18 __isl_give isl_set *isl_set_from_cloog_domain(CloogDomain *domain)
20 return (isl_set *)domain;
23 CloogScattering *cloog_scattering_from_isl_map(struct isl_map *map)
25 return (CloogScattering *)map;
28 __isl_give isl_map *isl_map_from_cloog_scattering(CloogScattering *scattering)
30 return (isl_map *)scattering;
34 /**
35 * Returns true if each scattering dimension is defined in terms
36 * of the original iterators.
38 int cloog_scattering_fully_specified(CloogScattering *scattering,
39 CloogDomain *domain)
41 isl_map *map = isl_map_from_cloog_scattering(scattering);
42 return isl_map_is_single_valued(map);
46 CloogConstraintSet *cloog_domain_constraints(CloogDomain *domain)
48 isl_basic_set *bset;
49 isl_set *set = isl_set_from_cloog_domain(domain);
50 assert(isl_set_n_basic_set(set) == 1);
51 bset = isl_set_copy_basic_set(set);
52 return cloog_constraint_set_from_isl_basic_set(bset);
56 void cloog_domain_print_constraints(FILE *foo, CloogDomain *domain,
57 int print_number)
59 isl_basic_set *bset;
60 isl_set *set = isl_set_from_cloog_domain(domain);
62 if (print_number)
63 isl_set_print(set, foo, 0, ISL_FORMAT_EXT_POLYLIB);
64 else {
65 assert(isl_set_n_basic_set(set) == 1);
66 bset = isl_set_copy_basic_set(set);
67 isl_basic_set_print(bset, foo,
68 0, NULL, NULL, ISL_FORMAT_POLYLIB);
69 isl_basic_set_free(bset);
74 void cloog_scattering_print_constraints(FILE *foo, CloogScattering *scattering)
76 isl_map *map = isl_map_from_cloog_scattering(scattering);
77 isl_map_print(map, foo, 0, ISL_FORMAT_EXT_POLYLIB);
81 void cloog_domain_free(CloogDomain * domain)
83 isl_set *set = isl_set_from_cloog_domain(domain);
84 isl_set_free(set);
88 void cloog_scattering_free(CloogScattering *scatt)
90 isl_map *map = isl_map_from_cloog_scattering(scatt);
91 isl_map_free(map);
95 CloogDomain * cloog_domain_copy(CloogDomain * domain)
97 isl_set *set = isl_set_from_cloog_domain(domain);
98 return cloog_domain_from_isl_set(isl_set_copy(set));
103 * cloog_domain_convex function:
104 * Computes the convex hull of domain.
106 CloogDomain *cloog_domain_convex(CloogDomain *domain)
108 isl_set *set = isl_set_from_cloog_domain(domain);
109 set = isl_set_from_basic_set(isl_set_convex_hull(isl_set_copy(set)));
110 return cloog_domain_from_isl_set(set);
115 * cloog_domain_simple_convex:
116 * Given a list (union) of polyhedra, this function returns a "simple"
117 * convex hull of this union. In particular, the constraints of the
118 * the returned polyhedron consist of (parametric) lower and upper
119 * bounds on individual variables and constraints that appear in the
120 * original polyhedra.
122 CloogDomain *cloog_domain_simple_convex(CloogDomain *domain)
124 struct isl_basic_set *hull;
125 isl_set *set = isl_set_from_cloog_domain(domain);
126 unsigned dim = isl_set_dim(set, isl_dim_set);
128 if (cloog_domain_isconvex(domain))
129 return cloog_domain_copy(domain);
131 if (dim == 0)
132 return cloog_domain_convex(domain);
134 hull = isl_set_bounded_simple_hull(isl_set_copy(set));
135 return cloog_domain_from_isl_set(isl_set_from_basic_set(hull));
140 * cloog_domain_simplify function:
141 * Given two polyhedral domains (dom1) and (dom2),
142 * this function finds the largest domain set (or the smallest list
143 * of non-redundant constraints), that when intersected with polyhedral
144 * domain (dom2) equals (dom1)intersect(dom2). The output is a new CloogDomain
145 * structure with a polyhedral domain with the "redundant" constraints removed.
146 * NB: the second domain is required not to be a union.
148 CloogDomain *cloog_domain_simplify(CloogDomain *dom1, CloogDomain *dom2)
150 isl_set *set1 = isl_set_from_cloog_domain(dom1);
151 isl_set *set2 = isl_set_from_cloog_domain(dom2);
152 set1 = isl_set_gist(isl_set_copy(set1), isl_set_copy(set2));
153 return cloog_domain_from_isl_set(set1);
158 * cloog_domain_union function:
159 * This function returns a new polyhedral domain which is the union of
160 * two polyhedral domains (dom1) U (dom2).
161 * Frees dom1 and dom2;
163 CloogDomain *cloog_domain_union(CloogDomain *dom1, CloogDomain *dom2)
165 isl_set *set1 = isl_set_from_cloog_domain(dom1);
166 isl_set *set2 = isl_set_from_cloog_domain(dom2);
167 set1 = isl_set_union(set1, set2);
168 return cloog_domain_from_isl_set(set1);
174 * cloog_domain_intersection function:
175 * This function returns a new polyhedral domain which is the intersection of
176 * two polyhedral domains (dom1) \cap (dom2).
178 CloogDomain *cloog_domain_intersection(CloogDomain *dom1, CloogDomain *dom2)
180 isl_set *set1 = isl_set_from_cloog_domain(dom1);
181 isl_set *set2 = isl_set_from_cloog_domain(dom2);
182 set1 = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
183 return cloog_domain_from_isl_set(set1);
188 * cloog_domain_difference function:
189 * Returns the set difference domain \ minus.
191 CloogDomain *cloog_domain_difference(CloogDomain *domain, CloogDomain *minus)
193 isl_set *set1 = isl_set_from_cloog_domain(domain);
194 isl_set *set2 = isl_set_from_cloog_domain(minus);
195 set1 = isl_set_subtract(isl_set_copy(set1), isl_set_copy(set2));
196 return cloog_domain_from_isl_set(set1);
201 * cloog_domain_sort function:
202 * This function topologically sorts (nb_doms) domains. Here (doms) is an
203 * array of pointers to CloogDomains, (nb_doms) is the number of domains,
204 * (level) is the level to consider for partial ordering (nb_par) is the
205 * parameter space dimension, (permut) if not NULL, is an array of (nb_doms)
206 * integers that contains a permutation specification after call in order to
207 * apply the topological sorting.
209 void cloog_domain_sort(CloogDomain **doms, unsigned nb_doms, unsigned level,
210 int *permut)
212 int i, j, k, cmp;
213 struct isl_ctx *ctx;
214 unsigned char **follows;
215 isl_set *set_i, *set_j;
216 isl_basic_set *bset_i, *bset_j;
218 if (!nb_doms)
219 return;
220 set_i = isl_set_from_cloog_domain(doms[0]);
221 ctx = isl_set_get_ctx(set_i);
222 for (i = 0; i < nb_doms; i++) {
223 set_i = isl_set_from_cloog_domain(doms[i]);
224 assert(isl_set_n_basic_set(set_i) == 1);
227 follows = isl_alloc_array(ctx, unsigned char *, nb_doms);
228 assert(follows);
229 for (i = 0; i < nb_doms; ++i) {
230 follows[i] = isl_alloc_array(ctx, unsigned char, nb_doms);
231 assert(follows[i]);
232 for (j = 0; j < nb_doms; ++j)
233 follows[i][j] = 0;
236 for (i = 1; i < nb_doms; ++i) {
237 for (j = 0; j < i; ++j) {
238 if (follows[i][j] || follows[j][i])
239 continue;
240 set_i = isl_set_from_cloog_domain(doms[i]);
241 set_j = isl_set_from_cloog_domain(doms[j]);
242 bset_i = isl_set_copy_basic_set(set_i);
243 bset_j = isl_set_copy_basic_set(set_j);
244 cmp = isl_basic_set_compare_at(bset_i, bset_j, level-1);
245 isl_basic_set_free(bset_i);
246 isl_basic_set_free(bset_j);
247 if (!cmp)
248 continue;
249 if (cmp > 0) {
250 follows[i][j] = 1;
251 for (k = 0; k < i; ++k)
252 follows[i][k] |= follows[j][k];
253 } else {
254 follows[j][i] = 1;
255 for (k = 0; k < i; ++k)
256 follows[k][i] |= follows[k][j];
261 for (i = 0, j = 0; i < nb_doms; j = (j + 1) % nb_doms) {
262 for (k = 0; k < nb_doms; ++k)
263 if (follows[j][k])
264 break;
265 if (k < nb_doms)
266 continue;
267 for (k = 0; k < nb_doms; ++k)
268 follows[k][j] = 0;
269 follows[j][j] = 1;
270 permut[i] = 1 + j;
271 ++i;
274 for (i = 0; i < nb_doms; ++i)
275 free(follows[i]);
276 free(follows);
281 * Check whether there is or may be any value of dom1 at the given level
282 * that is greater than or equal to a value of dom2 at the same level.
284 * Return
285 * 1 is there is or may be a greater-than pair.
286 * 0 if there is no greater-than pair, but there may be an equal-to pair
287 * -1 if there is definitely no such pair
289 int cloog_domain_follows(CloogDomain *dom1, CloogDomain *dom2, unsigned level)
291 isl_set *set1 = isl_set_from_cloog_domain(dom1);
292 isl_set *set2 = isl_set_from_cloog_domain(dom2);
293 int follows;
295 follows = isl_set_follows_at(set1, set2, level - 1);
296 assert(follows >= -1);
298 return follows;
303 * cloog_domain_empty function:
304 * Returns an empty domain of the same dimensions as template.
306 CloogDomain *cloog_domain_empty(CloogDomain *template)
308 isl_set *set = isl_set_from_cloog_domain(template);
309 return cloog_domain_from_isl_set(isl_set_empty_like(set));
314 * Return 1 if the specified dimension has both an upper and a lower bound.
316 int cloog_domain_is_bounded(CloogDomain *dom, unsigned level)
318 isl_set *set = isl_set_from_cloog_domain(dom);
319 return isl_set_dim_is_bounded(set, isl_dim_set, level - 1);
323 /******************************************************************************
324 * Structure display function *
325 ******************************************************************************/
329 * cloog_domain_print_structure :
330 * this function is a more human-friendly way to display the CloogDomain data
331 * structure, it only shows the constraint system and includes an indentation
332 * level (level) in order to work with others print_structure functions.
334 void cloog_domain_print_structure(FILE *file, CloogDomain *domain, int level,
335 const char *name)
337 int i ;
338 isl_set *set = isl_set_from_cloog_domain(domain);
340 /* Go to the right level. */
341 for (i = 0; i < level; i++)
342 fprintf(file, "|\t");
344 if (!set) {
345 fprintf(file, "+-- Null CloogDomain\n");
346 return;
348 fprintf(file, "+-- %s\n", name);
349 for (i = 0; i < level+1; ++i)
350 fprintf(file, "|\t");
352 isl_set_print(set, file, 0, ISL_FORMAT_ISL);
354 fprintf(file, "\n");
358 /******************************************************************************
359 * Memory deallocation function *
360 ******************************************************************************/
363 void cloog_domain_list_free(CloogDomainList *list)
365 CloogDomainList *next;
367 for ( ; list; list = next) {
368 next = list->next;
369 cloog_domain_free(list->domain);
370 free(list);
376 * cloog_scattering_list_free function:
377 * This function frees the allocated memory for a CloogScatteringList structure.
379 void cloog_scattering_list_free(CloogScatteringList *list)
381 while (list != NULL) {
382 CloogScatteringList *temp = list->next;
383 isl_map *map = isl_map_from_cloog_scattering(list->scatt);
384 isl_map_free(map);
385 free(list);
386 list = temp;
391 /******************************************************************************
392 * Reading function *
393 ******************************************************************************/
397 * cloog_domain_read_context function:
398 * Read parameter domain.
400 CloogDomain *cloog_domain_read_context(CloogState *state, FILE *input)
402 struct isl_ctx *ctx = state->backend->ctx;
403 isl_set *set;
405 set = isl_set_read_from_file(ctx, input, 0);
406 set = isl_set_move_dims(set, isl_dim_param, 0,
407 isl_dim_set, 0, isl_set_dim(set, isl_dim_set));
409 return cloog_domain_from_isl_set(set);
414 * cloog_domain_from_context
415 * Reinterpret context by turning parameters into variables.
417 CloogDomain *cloog_domain_from_context(CloogDomain *context)
419 isl_set *set = isl_set_from_cloog_domain(context);
421 set = isl_set_move_dims(set, isl_dim_set, 0,
422 isl_dim_param, 0, isl_set_dim(set, isl_dim_param));
424 return cloog_domain_from_isl_set(set);
429 * cloog_domain_union_read function:
430 * This function reads a union of polyhedra into a file (input) and
431 * returns a pointer to a CloogDomain containing the read information.
433 CloogDomain *cloog_domain_union_read(CloogState *state,
434 FILE *input, int nb_parameters)
436 struct isl_ctx *ctx = state->backend->ctx;
437 struct isl_set *set;
439 set = isl_set_read_from_file(ctx, input, nb_parameters);
440 return cloog_domain_from_isl_set(set);
445 * cloog_domain_read_scattering function:
446 * This function reads in a scattering function from the file input.
448 * We try to read the scattering relation as a map, but if it is
449 * specified in the original PolyLib format, then isl_map_read_from_file
450 * will treat the input as a set return a map with zero input dimensions.
451 * In this case, we need to decompose the set into a map from
452 * scattering dimensions to domain dimensions and then invert the
453 * resulting map.
455 CloogScattering *cloog_domain_read_scattering(CloogDomain *domain, FILE *input)
457 isl_set *set = isl_set_from_cloog_domain(domain);
458 isl_ctx *ctx = isl_set_get_ctx(set);
459 struct isl_map *scat;
460 unsigned nparam;
461 unsigned dim;
462 unsigned n_scat;
464 dim = isl_set_dim(set, isl_dim_set);
465 nparam = isl_set_dim(set, isl_dim_param);
466 scat = isl_map_read_from_file(ctx, input, nparam);
467 if (isl_map_dim(scat, isl_dim_in) != dim) {
468 n_scat = isl_map_dim(scat, isl_dim_out) - dim;
469 scat = isl_map_move_dims(scat, isl_dim_in, 0,
470 isl_dim_out, n_scat, dim);
472 return cloog_scattering_from_isl_map(scat);
475 /******************************************************************************
476 * CloogMatrix Reading function *
477 ******************************************************************************/
480 * isl_constraint_read_from_matrix:
481 * Convert a single line of a matrix to a isl_constraint.
482 * Returns a pointer to the constraint if successful; NULL otherwise.
484 static struct isl_constraint *isl_constraint_read_from_matrix(
485 struct isl_dim *dim, cloog_int_t *row)
487 struct isl_constraint *constraint;
488 int j;
489 int nvariables = isl_dim_size(dim, isl_dim_set);
490 int nparam = isl_dim_size(dim, isl_dim_param);
492 if (cloog_int_is_zero(row[0]))
493 constraint = isl_equality_alloc(dim);
494 else
495 constraint = isl_inequality_alloc(dim);
497 for (j = 0; j < nvariables; ++j)
498 isl_constraint_set_coefficient(constraint, isl_dim_out, j,
499 row[1 + j]);
501 for (j = 0; j < nparam; ++j)
502 isl_constraint_set_coefficient(constraint, isl_dim_param, j,
503 row[1 + nvariables + j]);
505 isl_constraint_set_constant(constraint, row[1 + nvariables + nparam]);
507 return constraint;
511 * isl_basic_set_read_from_matrix:
512 * Convert matrix to basic_set. The matrix contains nparam parameter columns.
513 * Returns a pointer to the basic_set if successful; NULL otherwise.
515 static struct isl_basic_set *isl_basic_set_read_from_matrix(struct isl_ctx *ctx,
516 CloogMatrix* matrix, int nparam)
518 struct isl_dim *dim;
519 struct isl_basic_set *bset;
520 int i;
521 unsigned nrows, ncolumns;
523 nrows = matrix->NbRows;
524 ncolumns = matrix->NbColumns;
525 int nvariables = ncolumns - 2 - nparam;
527 dim = isl_dim_set_alloc(ctx, nparam, nvariables);
529 bset = isl_basic_set_universe(isl_dim_copy(dim));
531 for (i = 0; i < nrows; ++i) {
532 cloog_int_t *row = matrix->p[i];
533 struct isl_constraint *constraint =
534 isl_constraint_read_from_matrix(isl_dim_copy(dim), row);
535 bset = isl_basic_set_add_constraint(bset, constraint);
538 isl_dim_free(dim);
540 return bset;
544 * cloog_domain_from_cloog_matrix:
545 * Create a CloogDomain containing the constraints described in matrix.
546 * nparam is the number of parameters contained in the domain.
547 * Returns a pointer to the CloogDomain if successful; NULL otherwise.
549 CloogDomain *cloog_domain_from_cloog_matrix(CloogState *state,
550 CloogMatrix *matrix, int nparam)
552 struct isl_ctx *ctx = state->backend->ctx;
553 struct isl_basic_set *bset;
555 bset = isl_basic_set_read_from_matrix(ctx, matrix, nparam);
557 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
561 * cloog_scattering_from_cloog_matrix:
562 * Create a CloogScattering containing the constraints described in matrix.
563 * nparam is the number of parameters contained in the domain.
564 * Returns a pointer to the CloogScattering if successful; NULL otherwise.
566 CloogScattering *cloog_scattering_from_cloog_matrix(CloogState *state,
567 CloogMatrix *matrix, int nb_scat, int nb_par)
569 struct isl_ctx *ctx = state->backend->ctx;
570 struct isl_basic_set *bset;
571 struct isl_basic_map *scat;
572 struct isl_dim *dims;
573 unsigned dim;
575 bset = isl_basic_set_read_from_matrix(ctx, matrix, nb_par);
576 dim = isl_basic_set_n_dim(bset) - nb_scat;
577 dims = isl_dim_alloc(ctx, nb_par, nb_scat, dim);
579 scat = isl_basic_map_from_basic_set(bset, dims);
580 scat = isl_basic_map_reverse(scat);
581 return cloog_scattering_from_isl_map(isl_map_from_basic_map(scat));
585 /******************************************************************************
586 * Processing functions *
587 ******************************************************************************/
592 * cloog_domain_isempty function:
594 int cloog_domain_isempty(CloogDomain *domain)
596 isl_set *set = isl_set_from_cloog_domain(domain);
597 return isl_set_is_empty(set);
602 * cloog_domain_universe function:
603 * This function returns the complete dim-dimensional space.
605 CloogDomain *cloog_domain_universe(CloogState *state, unsigned dim)
607 struct isl_dim *dims;
608 struct isl_basic_set *bset;
610 dims = isl_dim_set_alloc(state->backend->ctx, 0, dim);
611 bset = isl_basic_set_universe(dims);
612 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
617 * cloog_domain_project function:
618 * This function returns the projection of
619 * (domain) on the (level) first dimensions (i.e. outer loops).
621 CloogDomain *cloog_domain_project(CloogDomain *domain, int level)
623 isl_set *set = isl_set_from_cloog_domain(domain);
624 set = isl_set_remove_dims(isl_set_copy(set), isl_dim_set,
625 level, isl_set_n_dim(set) - level);
626 set = isl_set_compute_divs(set);
627 if (level > 0)
628 set = isl_set_remove_divs_involving_dims(set,
629 isl_dim_set, level - 1, 1);
630 return cloog_domain_from_isl_set(set);
635 * cloog_domain_extend function:
636 * This function returns the (domain) given as input with (dim)
637 * dimensions and (nb_par) parameters.
638 * This function does not free (domain), and returns a new CloogDomain.
640 CloogDomain *cloog_domain_extend(CloogDomain *domain, int dim)
642 isl_set *set = isl_set_from_cloog_domain(domain);
643 set = isl_set_extend(isl_set_copy(set), isl_set_n_param(set), dim);
644 return cloog_domain_from_isl_set(set);
649 * cloog_domain_never_integral function:
650 * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0.
651 * There is no need to check for such constraints explicitly for the isl
652 * backend.
654 int cloog_domain_never_integral(CloogDomain * domain)
656 isl_set *set = isl_set_from_cloog_domain(domain);
657 return isl_set_is_empty(set);
662 * Check whether the loop at "level" is executed at most once.
663 * We construct a map that maps all remaining variables to this iterator
664 * and check whether this map is single valued.
666 * Alternatively, we could have mapped the domain through a mapping
667 * [p] -> { [..., i] -> [..., i'] : i' > i }
668 * and then taken the intersection of the original domain and the transformed
669 * domain. If this intersection is empty, then the corresponding
670 * loop is executed at most once.
672 int cloog_domain_is_otl(CloogDomain *domain, int level)
674 int otl;
675 isl_set *set = isl_set_from_cloog_domain(domain);
676 isl_map *map;
678 map = isl_map_from_domain(isl_set_copy(set));
679 map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_in, level - 1, 1);
680 otl = isl_map_is_single_valued(map);
681 isl_map_free(map);
683 return otl;
688 * cloog_domain_stride function:
689 * This function finds the stride imposed to unknown with the column number
690 * 'strided_level' in order to be integral. For instance, if we have a
691 * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral
692 * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to
693 * the unknown i. The function returns the imposed stride in a parameter field.
694 * - domain is the set of constraint we have to consider,
695 * - strided_level is the column number of the unknown for which a stride have
696 * to be found,
697 * - looking_level is the column number of the unknown that impose a stride to
698 * the first unknown.
699 * - stride is the stride that is returned back as a function parameter.
700 * - offset is the value of the constant c if the condition is of the shape
701 * (i + c)%s = 0, s being the stride.
703 void cloog_domain_stride(CloogDomain *domain, int strided_level,
704 cloog_int_t *stride, cloog_int_t *offset)
706 isl_set *set = isl_set_from_cloog_domain(domain);
707 isl_set_dim_residue_class(set, strided_level - 1, stride, offset);
708 if (!isl_int_is_zero(*offset))
709 isl_int_sub(*offset, *stride, *offset);
710 return;
714 struct cloog_can_stride {
715 int level;
716 int can_stride;
719 static int constraint_can_stride(__isl_take isl_constraint *c, void *user)
721 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
722 int i;
723 isl_int v;
724 unsigned n_div;
726 isl_int_init(v);
727 isl_constraint_get_coefficient(c, isl_dim_set, ccs->level - 1, &v);
728 if (isl_int_is_pos(v)) {
729 n_div = isl_constraint_dim(c, isl_dim_div);
730 for (i = 0; i < n_div; ++i) {
731 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
732 if (!isl_int_is_zero(v))
733 break;
735 if (i < n_div)
736 ccs->can_stride = 0;
738 isl_int_clear(v);
739 isl_constraint_free(c);
741 return 0;
744 static int basic_set_can_stride(__isl_take isl_basic_set *bset, void *user)
746 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
747 int r;
749 r = isl_basic_set_foreach_constraint(bset, constraint_can_stride, ccs);
750 isl_basic_set_free(bset);
751 return r;
756 * Return 1 if CLooG is allowed to perform stride detection on level "level"
757 * and 0 otherwise.
758 * Currently, stride detection is only allowed when none of the lower
759 * bound constraints involve any existentially quantified variables.
760 * The reason is that the current isl interface does not make it
761 * easy to construct an integer division that depends on other integer
762 * divisions.
763 * By not allowing existentially quantified variables in the constraints,
764 * we can ignore them in cloog_domain_stride_lower_bound.
766 int cloog_domain_can_stride(CloogDomain *domain, int level)
768 struct cloog_can_stride ccs = { level, 1 };
769 isl_set *set = isl_set_from_cloog_domain(domain);
770 int r;
771 r = isl_set_foreach_basic_set(set, basic_set_can_stride, &ccs);
772 assert(r == 0);
773 return ccs.can_stride;
777 struct cloog_stride_lower {
778 int level;
779 CloogStride *stride;
780 isl_set *set;
781 isl_basic_set *bounds;
784 /* If the given constraint is a lower bound on csl->level, then add
785 * a lower bound to csl->bounds that makes sure that the remainder
786 * of the smallest value on division by csl->stride is equal to csl->offset.
788 * In particular, the given lower bound is of the form
790 * a i + f >= 0
792 * where f may depend on the parameters and other iterators.
793 * The stride is s and the offset is d.
794 * The lower bound -f/a may not satisfy the above condition. In fact,
795 * it may not even be integral. We want to round this value of i up
796 * to the nearest value that satisfies the condition and add the corresponding
797 * lower bound constraint. This nearest value is obtained by rounding
798 * i - d up to the nearest multiple of s.
799 * That is, we first subtract d
801 * i' = -f/a - d
803 * then we round up to the nearest multiple of s
805 * i'' = s * ceil(i'/s)
807 * and finally, we add d again
809 * i''' = i'' + d
811 * and impose the constraint i >= i'''.
813 * We find
815 * i'' = s * ceil((-f - a * d)/(a * s)) = - s * floor((f + a * d)/(a * s))
817 * i >= - s * floor((f + a * d)/(a * s)) + d
819 * or
820 * i + s * floor((f + a * d)/(a * s)) - d >= 0
822 static int constraint_stride_lower(__isl_take isl_constraint *c, void *user)
824 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
825 int i;
826 isl_int v;
827 isl_int t;
828 isl_constraint *bound;
829 isl_div *div;
830 int pos;
831 unsigned nparam, nvar;
833 isl_int_init(v);
834 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
835 if (!isl_int_is_pos(v)) {
836 isl_int_clear(v);
837 isl_constraint_free(c);
839 return 0;
842 isl_int_init(t);
844 nparam = isl_constraint_dim(c, isl_dim_param);
845 nvar = isl_constraint_dim(c, isl_dim_set);
846 bound = isl_inequality_alloc(isl_basic_set_get_dim(csl->bounds));
847 div = isl_div_alloc(isl_basic_set_get_dim(csl->bounds));
848 isl_int_mul(t, v, csl->stride->stride);
849 isl_div_set_denominator(div, t);
850 for (i = 0; i < nparam; ++i) {
851 isl_constraint_get_coefficient(c, isl_dim_param, i, &t);
852 isl_div_set_coefficient(div, isl_dim_param, i, t);
854 for (i = 0; i < nvar; ++i) {
855 if (i == csl->level - 1)
856 continue;
857 isl_constraint_get_coefficient(c, isl_dim_set, i, &t);
858 isl_div_set_coefficient(div, isl_dim_set, i, t);
860 isl_constraint_get_constant(c, &t);
861 isl_int_addmul(t, v, csl->stride->offset);
862 isl_div_set_constant(div, t);
864 bound = isl_constraint_add_div(bound, div, &pos);
865 isl_int_set_si(t, 1);
866 isl_constraint_set_coefficient(bound, isl_dim_set,
867 csl->level - 1, t);
868 isl_constraint_set_coefficient(bound, isl_dim_div, pos,
869 csl->stride->stride);
870 isl_int_neg(t, csl->stride->offset);
871 isl_constraint_set_constant(bound, t);
872 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
874 isl_int_clear(v);
875 isl_int_clear(t);
876 isl_constraint_free(c);
878 return 0;
881 /* This functions performs essentially the same operation as
882 * constraint_stride_lower, the only difference being that the offset d
883 * is not a constant, but an affine expression in terms of the parameters
884 * and earlier variables. In particular the affine expression is equal
885 * to the coefficients of stride->constraint multiplied by stride->factor.
886 * As in constraint_stride_lower, we add an extra bound
888 * i + s * floor((f + a * d)/(a * s)) - d >= 0
890 * for each lower bound
892 * a i + f >= 0
894 * where d is not the aforementioned affine expression.
896 static int constraint_stride_lower_c(__isl_take isl_constraint *c, void *user)
898 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
899 int i;
900 isl_int v;
901 isl_int t, u;
902 isl_constraint *bound;
903 isl_constraint *csl_c;
904 isl_div *div;
905 int pos;
906 unsigned nparam, nvar;
908 isl_int_init(v);
909 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
910 if (!isl_int_is_pos(v)) {
911 isl_int_clear(v);
912 isl_constraint_free(c);
914 return 0;
917 csl_c = &csl->stride->constraint->isl;
919 isl_int_init(t);
920 isl_int_init(u);
922 nparam = isl_constraint_dim(c, isl_dim_param);
923 nvar = isl_constraint_dim(c, isl_dim_set);
924 bound = isl_inequality_alloc(isl_basic_set_get_dim(csl->bounds));
925 div = isl_div_alloc(isl_basic_set_get_dim(csl->bounds));
926 isl_int_mul(t, v, csl->stride->stride);
927 isl_div_set_denominator(div, t);
928 for (i = 0; i < nparam; ++i) {
929 isl_constraint_get_coefficient(c, isl_dim_param, i, &t);
930 isl_constraint_get_coefficient(csl_c, isl_dim_param, i, &u);
931 isl_int_mul(u, u, csl->stride->factor);
932 isl_int_addmul(t, v, u);
933 isl_div_set_coefficient(div, isl_dim_param, i, t);
934 isl_int_neg(u, u);
935 isl_constraint_set_coefficient(bound, isl_dim_param, i, u);
937 for (i = 0; i < nvar; ++i) {
938 if (i == csl->level - 1)
939 continue;
940 isl_constraint_get_coefficient(c, isl_dim_set, i, &t);
941 isl_constraint_get_coefficient(csl_c, isl_dim_set, i, &u);
942 isl_int_mul(u, u, csl->stride->factor);
943 isl_int_addmul(t, v, u);
944 isl_div_set_coefficient(div, isl_dim_set, i, t);
945 isl_int_neg(u, u);
946 isl_constraint_set_coefficient(bound, isl_dim_set, i, u);
948 isl_constraint_get_constant(c, &t);
949 isl_constraint_get_constant(csl_c, &u);
950 isl_int_mul(u, u, csl->stride->factor);
951 isl_int_addmul(t, v, u);
952 isl_div_set_constant(div, t);
953 isl_int_neg(u, u);
954 isl_constraint_set_constant(bound, u);
956 bound = isl_constraint_add_div(bound, div, &pos);
957 isl_int_set_si(t, 1);
958 isl_constraint_set_coefficient(bound, isl_dim_set,
959 csl->level - 1, t);
960 isl_constraint_set_coefficient(bound, isl_dim_div, pos,
961 csl->stride->stride);
962 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
964 isl_int_clear(u);
965 isl_int_clear(t);
966 isl_int_clear(v);
967 isl_constraint_free(c);
969 return 0;
972 static int basic_set_stride_lower(__isl_take isl_basic_set *bset, void *user)
974 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
975 int r;
977 csl->bounds = isl_basic_set_universe_like(bset);
978 if (csl->stride->constraint)
979 r = isl_basic_set_foreach_constraint(bset,
980 &constraint_stride_lower_c, csl);
981 else
982 r = isl_basic_set_foreach_constraint(bset,
983 &constraint_stride_lower, csl);
984 bset = isl_basic_set_intersect(bset, csl->bounds);
985 csl->set = isl_set_union(csl->set, isl_set_from_basic_set(bset));
987 return r;
991 * Update the lower bounds at level "level" to the given stride information.
992 * That is, make sure that the remainder on division by "stride"
993 * is equal to "offset".
995 CloogDomain *cloog_domain_stride_lower_bound(CloogDomain *domain, int level,
996 CloogStride *stride)
998 struct cloog_stride_lower csl;
999 isl_set *set = isl_set_from_cloog_domain(domain);
1000 int r;
1002 csl.stride = stride;
1003 csl.level = level;
1004 csl.set = isl_set_empty_like(set);
1006 r = isl_set_foreach_basic_set(set, basic_set_stride_lower, &csl);
1007 assert(r == 0);
1009 cloog_domain_free(domain);
1010 return cloog_domain_from_isl_set(csl.set);
1015 * cloog_domain_lazy_equal function:
1016 * This function returns 1 if the domains given as input are the same, 0 if it
1017 * is unable to decide.
1019 int cloog_domain_lazy_equal(CloogDomain *d1, CloogDomain *d2)
1021 isl_set *set1 = isl_set_from_cloog_domain(d1);
1022 isl_set *set2 = isl_set_from_cloog_domain(d2);
1023 return isl_set_fast_is_equal(set1, set2);
1026 struct cloog_bound_split {
1027 isl_set *set;
1028 int level;
1029 int lower;
1030 int upper;
1033 static int constraint_bound_split(__isl_take isl_constraint *c, void *user)
1035 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1036 isl_int v;
1037 int i;
1038 int handle = 0;
1040 isl_int_init(v);
1041 isl_constraint_get_coefficient(c, isl_dim_set, cbs->level - 1, &v);
1042 if (!cbs->lower && isl_int_is_pos(v))
1043 cbs->lower = handle = 1;
1044 else if (!cbs->upper && isl_int_is_neg(v))
1045 cbs->upper = handle = 1;
1046 if (handle) {
1047 for (i = 0; i < isl_set_dim(cbs->set, isl_dim_param); ++i) {
1048 isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
1049 if (isl_int_is_zero(v))
1050 continue;
1051 cbs->set = isl_set_split_dims(cbs->set,
1052 isl_dim_param, i, 1);
1055 isl_int_clear(v);
1056 isl_constraint_free(c);
1058 return (cbs->lower && cbs->upper) ? -1 : 0;
1061 static int basic_set_bound_split(__isl_take isl_basic_set *bset, void *user)
1063 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1064 int r;
1066 cbs->lower = 0;
1067 cbs->upper = 0;
1068 r = isl_basic_set_foreach_constraint(bset, constraint_bound_split, cbs);
1069 isl_basic_set_free(bset);
1070 return ((!cbs->lower || !cbs->upper) && r < 0) ? -1 : 0;
1074 * Return a union of sets S_i such that the convex hull of "dom",
1075 * when intersected with one the sets S_i, will have an upper and
1076 * lower bound for the dimension at "level" (provided "dom" itself
1077 * has such bounds for the dimensions).
1079 * We currently take a very simple approach. For each of the basic
1080 * sets in "dom" we pick a lower and an upper bound and split the
1081 * range of any parameter involved in these two bounds in a
1082 * nonnegative and a negative part. This ensures that the symbolic
1083 * constant in these two constraints are themselves bounded and
1084 * so there will be at least one upper and one lower bound
1085 * in the convex hull.
1087 CloogDomain *cloog_domain_bound_splitter(CloogDomain *dom, int level)
1089 struct cloog_bound_split cbs;
1090 isl_set *set = isl_set_from_cloog_domain(dom);
1091 int r;
1092 cbs.level = level;
1093 cbs.set = isl_set_universe_like(set);
1094 r = isl_set_foreach_basic_set(set, basic_set_bound_split, &cbs);
1095 assert(r == 0);
1096 return cloog_domain_from_isl_set(cbs.set);
1101 * cloog_scattering_lazy_block function:
1102 * This function returns 1 if the two scattering functions s1 and s2 given
1103 * as input are the same (except possibly for the final dimension, where we
1104 * allow a difference of 1), assuming that the domains on which this
1105 * scatterings are applied are the same.
1106 * In fact this function answers the question "can I
1107 * safely consider the two domains as only one with two statements (a block) ?".
1108 * - s1 and s2 are the two domains to check for blocking,
1109 * - scattering is the linked list of all domains,
1110 * - scattdims is the total number of scattering dimentions.
1112 int cloog_scattering_lazy_block(CloogScattering *s1, CloogScattering *s2,
1113 CloogScatteringList *scattering, int scattdims)
1115 int i;
1116 struct isl_dim *dim;
1117 struct isl_map *rel;
1118 struct isl_set *delta;
1119 isl_map *map1 = isl_map_from_cloog_scattering(s1);
1120 isl_map *map2 = isl_map_from_cloog_scattering(s2);
1121 int fixed, block;
1122 isl_int cst;
1123 unsigned n_scat;
1125 n_scat = isl_map_dim(map1, isl_dim_out);
1126 if (n_scat != isl_map_dim(map2, isl_dim_out))
1127 return 0;
1129 dim = isl_map_get_dim(map1);
1130 dim = isl_dim_domain(dim);
1131 rel = isl_map_identity(dim);
1132 rel = isl_map_apply_domain(rel, isl_map_copy(map1));
1133 rel = isl_map_apply_range(rel, isl_map_copy(map2));
1134 delta = isl_map_deltas(rel);
1135 isl_int_init(cst);
1136 for (i = 0; i < n_scat; ++i) {
1137 fixed = isl_set_fast_dim_is_fixed(delta, i, &cst);
1138 if (fixed != 1)
1139 break;
1140 if (i+1 < n_scat && !isl_int_is_zero(cst))
1141 break;
1142 if (!isl_int_is_zero(cst) && !isl_int_is_one(cst))
1143 break;
1145 block = i >= n_scat;
1146 isl_int_clear(cst);
1147 isl_set_free(delta);
1148 return block;
1153 * cloog_domain_lazy_disjoint function:
1154 * This function returns 1 if the domains given as input are disjoint, 0 if it
1155 * is unable to decide.
1157 int cloog_domain_lazy_disjoint(CloogDomain *d1, CloogDomain *d2)
1159 isl_set *set1 = isl_set_from_cloog_domain(d1);
1160 isl_set *set2 = isl_set_from_cloog_domain(d2);
1161 return isl_set_fast_is_disjoint(set1, set2);
1166 * cloog_scattering_list_lazy_same function:
1167 * This function returns 1 if two domains in the list are the same, 0 if it
1168 * is unable to decide.
1170 int cloog_scattering_list_lazy_same(CloogScatteringList *list)
1172 CloogScatteringList *one, *other;
1173 isl_map *one_map, *other_map;
1175 for (one = list; one; one = one->next) {
1176 one_map = isl_map_from_cloog_scattering(one->scatt);
1177 for (other = one->next; other; other = other->next) {
1178 other_map = isl_map_from_cloog_scattering(other->scatt);
1179 if (isl_map_fast_is_equal(one_map, other_map))
1180 return 1;
1183 return 0;
1186 int cloog_domain_dimension(CloogDomain * domain)
1188 isl_set *set = isl_set_from_cloog_domain(domain);
1189 return isl_set_dim(set, isl_dim_set);
1192 int cloog_domain_parameter_dimension(CloogDomain *domain)
1194 isl_set *set = isl_set_from_cloog_domain(domain);
1195 return isl_set_dim(set, isl_dim_param);
1198 int cloog_scattering_dimension(CloogScattering *scatt, CloogDomain *domain)
1200 isl_map *map = isl_map_from_cloog_scattering(scatt);
1201 return isl_map_dim(map, isl_dim_out);
1204 int cloog_domain_isconvex(CloogDomain * domain)
1206 isl_set *set = isl_set_from_cloog_domain(domain);
1207 return isl_set_n_basic_set(set) <= 1;
1212 * cloog_domain_cut_first function:
1213 * This function splits off and returns the first convex set in the
1214 * union "domain". The remainder of the union is returned in rest.
1215 * The original "domain" itself is destroyed and may not be used
1216 * after a call to this function.
1218 CloogDomain *cloog_domain_cut_first(CloogDomain *domain, CloogDomain **rest)
1220 isl_set *set = isl_set_from_cloog_domain(domain);
1221 struct isl_basic_set *first;
1223 first = isl_set_copy_basic_set(set);
1224 set = isl_set_drop_basic_set(set, first);
1225 *rest = cloog_domain_from_isl_set(set);
1227 return cloog_domain_from_isl_set(isl_set_from_basic_set(first));
1232 * Given a union domain, try to find a simpler representation
1233 * using fewer sets in the union.
1234 * The original "domain" itself is destroyed and may not be used
1235 * after a call to this function.
1237 CloogDomain *cloog_domain_simplify_union(CloogDomain *domain)
1239 isl_set *set = isl_set_from_cloog_domain(domain);
1240 return cloog_domain_from_isl_set(isl_set_coalesce(set));
1245 * cloog_scattering_lazy_isscalar function:
1246 * this function returns 1 if the scattering dimension 'dimension' in the
1247 * scattering 'scatt' is constant.
1248 * If value is not NULL, then it is set to the constant value of dimension.
1250 int cloog_scattering_lazy_isscalar(CloogScattering *scatt, int dimension,
1251 cloog_int_t *value)
1253 isl_map *map = isl_map_from_cloog_scattering(scatt);
1254 return isl_map_fast_is_fixed(map, isl_dim_out, dimension, value);
1259 * cloog_domain_lazy_isconstant function:
1260 * this function returns 1 if the dimension 'dimension' in the
1261 * domain 'domain' is constant.
1262 * If value is not NULL, then it is set to the constant value of dimension.
1264 int cloog_domain_lazy_isconstant(CloogDomain *domain, int dimension,
1265 cloog_int_t *value)
1267 isl_set *set = isl_set_from_cloog_domain(domain);
1268 return isl_set_fast_dim_is_fixed(set, dimension, value);
1273 * cloog_scattering_erase_dimension function:
1274 * this function returns a CloogDomain structure builds from 'domain' where
1275 * we removed the dimension 'dimension' and every constraint involving this
1276 * dimension.
1278 CloogScattering *cloog_scattering_erase_dimension(CloogScattering *scattering,
1279 int dimension)
1281 isl_map *map = isl_map_from_cloog_scattering(scattering);
1282 map = isl_map_remove_dims(isl_map_copy(map), isl_dim_out, dimension, 1);
1283 return cloog_scattering_from_isl_map(map);
1287 * cloog_domain_cube:
1288 * Construct and return a dim-dimensional cube, with values ranging
1289 * between min and max in each dimension.
1291 CloogDomain *cloog_domain_cube(CloogState *state,
1292 int dim, cloog_int_t min, cloog_int_t max)
1294 int i;
1295 struct isl_basic_set *cube;
1296 struct isl_basic_set *interval;
1297 struct isl_basic_set_list *list;
1299 if (dim == 0)
1300 return cloog_domain_universe(state, dim);
1302 interval = isl_basic_set_interval(state->backend->ctx, min, max);
1303 list = isl_basic_set_list_alloc(state->backend->ctx, dim);
1304 for (i = 0; i < dim; ++i)
1305 list = isl_basic_set_list_add(list, isl_basic_set_copy(interval));
1306 isl_basic_set_free(interval);
1307 cube = isl_basic_set_product(list);
1308 return cloog_domain_from_isl_set(isl_set_from_basic_set(cube));
1313 * cloog_domain_scatter function:
1314 * This function add the scattering (scheduling) informations to a domain.
1316 CloogDomain *cloog_domain_scatter(CloogDomain *domain, CloogScattering *scatt)
1318 isl_set *set = isl_set_from_cloog_domain(domain);
1319 isl_map *map = isl_map_from_cloog_scattering(scatt);
1321 map = isl_map_reverse(isl_map_copy(map));
1322 map = isl_map_intersect_range(map, set);
1323 return cloog_domain_from_isl_set(isl_set_from_map(map));
1326 static int add_domain_from_map(__isl_take isl_map *map, void *user)
1328 isl_dim *dim;
1329 const char *name;
1330 CloogDomain *domain;
1331 CloogScattering *scat;
1332 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1334 dim = isl_map_get_dim(map);
1335 name = isl_dim_get_tuple_name(dim, isl_dim_in);
1336 domain = cloog_domain_from_isl_set(isl_map_domain(isl_map_copy(map)));
1337 scat = cloog_scattering_from_isl_map(map);
1338 *ud = cloog_union_domain_add_domain(*ud, name, domain, scat, NULL);
1339 isl_dim_free(dim);
1341 return 0;
1345 * Construct a CloogUnionDomain from an isl_union_map representing
1346 * a global scattering function. The input is a mapping from different
1347 * spaces (different tuple names and possibly different dimensions)
1348 * to a common space. The iteration domains are set to the domains
1349 * in each space. The statement names are set to the names of the
1350 * spaces. The parameter names of the result are set to those of
1351 * the input, but the iterator and scattering dimension names are
1352 * left unspecified.
1354 CloogUnionDomain *cloog_union_domain_from_isl_union_map(
1355 __isl_take isl_union_map *umap)
1357 int i;
1358 int nparam;
1359 isl_dim *dim;
1360 CloogUnionDomain *ud;
1362 dim = isl_union_map_get_dim(umap);
1363 nparam = isl_dim_size(dim, isl_dim_param);
1365 ud = cloog_union_domain_alloc(nparam);
1367 for (i = 0; i < nparam; ++i) {
1368 const char *s = isl_dim_get_name(dim, isl_dim_param, i);
1369 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1371 isl_dim_free(dim);
1373 if (isl_union_map_foreach_map(umap, &add_domain_from_map, &ud) < 0) {
1374 isl_union_map_free(umap);
1375 cloog_union_domain_free(ud);
1376 assert(0);
1379 isl_union_map_free(umap);
1381 return ud;
1384 static int count_same_name(__isl_keep isl_dim *dim,
1385 enum isl_dim_type type, unsigned pos, const char *name)
1387 enum isl_dim_type t;
1388 unsigned p, s;
1389 int count = 0;
1390 int len = strlen(name);
1392 for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) {
1393 s = t == type ? pos : isl_dim_size(dim, t);
1394 for (p = 0; p < s; ++p) {
1395 const char *n = isl_dim_get_name(dim, t, p);
1396 if (n && !strncmp(n, name, len))
1397 count++;
1400 return count;
1403 static int add_domain(__isl_take isl_set *set, void *user)
1405 int i, nvar;
1406 isl_ctx *ctx;
1407 isl_dim *dim;
1408 char buffer[20];
1409 const char *name;
1410 CloogDomain *domain;
1411 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1413 ctx = isl_set_get_ctx(set);
1414 dim = isl_set_get_dim(set);
1415 name = isl_dim_get_tuple_name(dim, isl_dim_in);
1416 domain = cloog_domain_from_isl_set(set);
1417 *ud = cloog_union_domain_add_domain(*ud, name, domain, NULL, NULL);
1419 nvar = isl_dim_size(dim, isl_dim_set);
1420 for (i = 0; i < nvar; ++i) {
1421 char *long_name = NULL;
1422 int n;
1424 name = isl_dim_get_name(dim, isl_dim_set, i);
1425 if (!name) {
1426 snprintf(buffer, sizeof(buffer), "i%d", i);
1427 name = buffer;
1429 n = count_same_name(dim, isl_dim_set, i, name);
1430 if (n) {
1431 int size = strlen(name) + 10;
1432 long_name = isl_alloc_array(ctx, char, size);
1433 if (!long_name)
1434 cloog_die("memory overflow.\n");
1435 snprintf(long_name, size, "%s_%d", name, n);
1436 name = long_name;
1438 *ud = cloog_union_domain_set_name(*ud, CLOOG_ITER, i, name);
1439 free(long_name);
1441 isl_dim_free(dim);
1443 return 0;
1447 * Construct a CloogUnionDomain from an isl_union_set.
1448 * The statement names are set to the names of the
1449 * spaces. The parameter and iterator names of the result are set to those of
1450 * the input, but the scattering dimension names are left unspecified.
1452 CloogUnionDomain *cloog_union_domain_from_isl_union_set(
1453 __isl_take isl_union_set *uset)
1455 int i;
1456 int nparam;
1457 isl_dim *dim;
1458 CloogUnionDomain *ud;
1460 dim = isl_union_set_get_dim(uset);
1461 nparam = isl_dim_size(dim, isl_dim_param);
1463 ud = cloog_union_domain_alloc(nparam);
1465 for (i = 0; i < nparam; ++i) {
1466 const char *s = isl_dim_get_name(dim, isl_dim_param, i);
1467 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1469 isl_dim_free(dim);
1471 if (isl_union_set_foreach_set(uset, &add_domain, &ud) < 0) {
1472 isl_union_set_free(uset);
1473 cloog_union_domain_free(ud);
1474 assert(0);
1477 isl_union_set_free(uset);
1479 return ud;
1482 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
1483 static void Euclid(cloog_int_t a, cloog_int_t b,
1484 cloog_int_t *x, cloog_int_t *y, cloog_int_t *g)
1486 cloog_int_t c, d, e, f, tmp;
1488 cloog_int_init(c);
1489 cloog_int_init(d);
1490 cloog_int_init(e);
1491 cloog_int_init(f);
1492 cloog_int_init(tmp);
1493 cloog_int_abs(c, a);
1494 cloog_int_abs(d, b);
1495 cloog_int_set_si(e, 1);
1496 cloog_int_set_si(f, 0);
1497 while (cloog_int_is_pos(d)) {
1498 cloog_int_tdiv_q(tmp, c, d);
1499 cloog_int_mul(tmp, tmp, f);
1500 cloog_int_sub(e, e, tmp);
1501 cloog_int_tdiv_q(tmp, c, d);
1502 cloog_int_mul(tmp, tmp, d);
1503 cloog_int_sub(c, c, tmp);
1504 cloog_int_swap(c, d);
1505 cloog_int_swap(e, f);
1507 cloog_int_set(*g, c);
1508 if (cloog_int_is_zero(a))
1509 cloog_int_set_si(*x, 0);
1510 else if (cloog_int_is_pos(a))
1511 cloog_int_set(*x, e);
1512 else cloog_int_neg(*x, e);
1513 if (cloog_int_is_zero(b))
1514 cloog_int_set_si(*y, 0);
1515 else {
1516 cloog_int_mul(tmp, a, *x);
1517 cloog_int_sub(tmp, c, tmp);
1518 cloog_int_divexact(*y, tmp, b);
1520 cloog_int_clear(c);
1521 cloog_int_clear(d);
1522 cloog_int_clear(e);
1523 cloog_int_clear(f);
1524 cloog_int_clear(tmp);
1527 /* Construct a CloogStride from the given constraint for the given level,
1528 * if possible.
1529 * We first compute the gcd of the coefficients of the existentially
1530 * quantified variables and then remove any common factors it has
1531 * with the coefficient at the given level.
1532 * The result is the value of the stride and if it is not one,
1533 * the it is possible to construct a CloogStride.
1534 * The constraint leading to the stride is stored in the CloogStride
1535 * as well a value (factor) such that the product of this value
1536 * and the coefficient at the given level is equal to -1 modulo the stride.
1538 static CloogStride *construct_stride(isl_constraint *c, int level)
1540 int i, n, sign;
1541 isl_int v, m, gcd, stride, factor;
1542 CloogStride *s;
1544 if (!c)
1545 return NULL;
1547 isl_int_init(v);
1548 isl_int_init(m);
1549 isl_int_init(gcd);
1550 isl_int_init(factor);
1551 isl_int_init(stride);
1553 isl_constraint_get_coefficient(c, isl_dim_set, level - 1, &v);
1554 sign = isl_int_sgn(v);
1555 isl_int_abs(m, v);
1557 isl_int_set_si(gcd, 0);
1558 n = isl_constraint_dim(c, isl_dim_div);
1559 for (i = 0; i < n; ++i) {
1560 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
1561 isl_int_gcd(gcd, gcd, v);
1564 isl_int_gcd(v, m, gcd);
1565 isl_int_divexact(stride, gcd, v);
1567 if (isl_int_is_zero(stride) || isl_int_is_one(stride))
1568 s = NULL;
1569 else {
1570 Euclid(m, stride, &factor, &v, &gcd);
1571 if (sign > 0)
1572 isl_int_neg(factor, factor);
1574 c = isl_constraint_copy(c);
1575 s = cloog_stride_alloc_from_constraint(stride,
1576 cloog_constraint_from_isl_constraint(c), factor);
1579 isl_int_clear(stride);
1580 isl_int_clear(factor);
1581 isl_int_clear(gcd);
1582 isl_int_clear(m);
1583 isl_int_clear(v);
1585 return s;
1588 struct cloog_isl_find_stride_data {
1589 int level;
1590 CloogStride *stride;
1593 /* Check if the given constraint can be used to derive
1594 * a stride on the iterator identified by data->level.
1595 * We first check that there are some existentially quantified variables
1596 * and that the coefficient at data->level is non-zero.
1597 * Then we call construct_stride for further checks and the actual
1598 * construction of the CloogStride.
1600 static int find_stride(__isl_take isl_constraint *c, void *user)
1602 struct cloog_isl_find_stride_data *data;
1603 int n;
1604 isl_int v;
1606 data = (struct cloog_isl_find_stride_data *)user;
1608 if (data->stride) {
1609 isl_constraint_free(c);
1610 return 0;
1613 n = isl_constraint_dim(c, isl_dim_div);
1614 if (n == 0) {
1615 isl_constraint_free(c);
1616 return 0;
1619 isl_int_init(v);
1621 isl_constraint_get_coefficient(c, isl_dim_set, data->level - 1, &v);
1622 if (!isl_int_is_zero(v))
1623 data->stride = construct_stride(c, data->level);
1625 isl_int_clear(v);
1627 isl_constraint_free(c);
1629 return 0;
1632 /* Check if the given list of domains has a common stride on the given level.
1633 * If so, return a pointer to a CloogStride object. If not, return NULL.
1635 * We project out all later variables, take the union and compute
1636 * the affine hull of the union. Then we check the (equality)
1637 * constraints in this affine hull for imposing a stride.
1639 CloogStride *cloog_domain_list_stride(CloogDomainList *list, int level)
1641 struct cloog_isl_find_stride_data data = { level, NULL };
1642 isl_set *set;
1643 isl_basic_set *aff;
1644 int first = level;
1645 int n;
1646 int r;
1648 set = isl_set_from_cloog_domain(list->domain);
1649 n = isl_set_dim(set, isl_dim_set) - first;
1650 set = isl_set_project_out(isl_set_copy(set), isl_dim_set, first, n);
1652 for (list = list->next; list; list = list->next) {
1653 isl_set *set_i = isl_set_from_cloog_domain(list->domain);
1654 n = isl_set_dim(set_i, isl_dim_set) - first;
1655 set_i = isl_set_project_out(isl_set_copy(set_i),
1656 isl_dim_set, first, n);
1657 set = isl_set_union(set, set_i);
1659 aff = isl_set_affine_hull(set);
1661 r = isl_basic_set_foreach_constraint(aff, &find_stride, &data);
1662 assert(r == 0);
1664 isl_basic_set_free(aff);
1666 return data.stride;