cloog_domain_simple_convex: always compute simple hull
[cloog.git] / source / isl / domain.c
blob127c5b9ab16602bceb04c956501a739728a4b7bb
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 hull = isl_set_bounded_simple_hull(isl_set_copy(set));
132 return cloog_domain_from_isl_set(isl_set_from_basic_set(hull));
137 * cloog_domain_simplify function:
138 * Given two polyhedral domains (dom1) and (dom2),
139 * this function finds the largest domain set (or the smallest list
140 * of non-redundant constraints), that when intersected with polyhedral
141 * domain (dom2) equals (dom1)intersect(dom2). The output is a new CloogDomain
142 * structure with a polyhedral domain with the "redundant" constraints removed.
143 * NB: the second domain is required not to be a union.
145 CloogDomain *cloog_domain_simplify(CloogDomain *dom1, CloogDomain *dom2)
147 isl_set *set1 = isl_set_from_cloog_domain(dom1);
148 isl_set *set2 = isl_set_from_cloog_domain(dom2);
149 set1 = isl_set_gist(isl_set_copy(set1), isl_set_copy(set2));
150 return cloog_domain_from_isl_set(set1);
155 * cloog_domain_union function:
156 * This function returns a new polyhedral domain which is the union of
157 * two polyhedral domains (dom1) U (dom2).
158 * Frees dom1 and dom2;
160 CloogDomain *cloog_domain_union(CloogDomain *dom1, CloogDomain *dom2)
162 isl_set *set1 = isl_set_from_cloog_domain(dom1);
163 isl_set *set2 = isl_set_from_cloog_domain(dom2);
164 set1 = isl_set_union(set1, set2);
165 return cloog_domain_from_isl_set(set1);
171 * cloog_domain_intersection function:
172 * This function returns a new polyhedral domain which is the intersection of
173 * two polyhedral domains (dom1) \cap (dom2).
175 CloogDomain *cloog_domain_intersection(CloogDomain *dom1, CloogDomain *dom2)
177 isl_set *set1 = isl_set_from_cloog_domain(dom1);
178 isl_set *set2 = isl_set_from_cloog_domain(dom2);
179 set1 = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
180 return cloog_domain_from_isl_set(set1);
185 * cloog_domain_difference function:
186 * Returns the set difference domain \ minus.
188 CloogDomain *cloog_domain_difference(CloogDomain *domain, CloogDomain *minus)
190 isl_set *set1 = isl_set_from_cloog_domain(domain);
191 isl_set *set2 = isl_set_from_cloog_domain(minus);
192 set1 = isl_set_subtract(isl_set_copy(set1), isl_set_copy(set2));
193 return cloog_domain_from_isl_set(set1);
198 * cloog_domain_sort function:
199 * This function topologically sorts (nb_doms) domains. Here (doms) is an
200 * array of pointers to CloogDomains, (nb_doms) is the number of domains,
201 * (level) is the level to consider for partial ordering (nb_par) is the
202 * parameter space dimension, (permut) if not NULL, is an array of (nb_doms)
203 * integers that contains a permutation specification after call in order to
204 * apply the topological sorting.
206 void cloog_domain_sort(CloogDomain **doms, unsigned nb_doms, unsigned level,
207 int *permut)
209 int i, j, k, cmp;
210 struct isl_ctx *ctx;
211 unsigned char **follows;
212 isl_set *set_i, *set_j;
213 isl_basic_set *bset_i, *bset_j;
215 if (!nb_doms)
216 return;
217 set_i = isl_set_from_cloog_domain(doms[0]);
218 ctx = isl_set_get_ctx(set_i);
219 for (i = 0; i < nb_doms; i++) {
220 set_i = isl_set_from_cloog_domain(doms[i]);
221 assert(isl_set_n_basic_set(set_i) == 1);
224 follows = isl_alloc_array(ctx, unsigned char *, nb_doms);
225 assert(follows);
226 for (i = 0; i < nb_doms; ++i) {
227 follows[i] = isl_alloc_array(ctx, unsigned char, nb_doms);
228 assert(follows[i]);
229 for (j = 0; j < nb_doms; ++j)
230 follows[i][j] = 0;
233 for (i = 1; i < nb_doms; ++i) {
234 for (j = 0; j < i; ++j) {
235 if (follows[i][j] || follows[j][i])
236 continue;
237 set_i = isl_set_from_cloog_domain(doms[i]);
238 set_j = isl_set_from_cloog_domain(doms[j]);
239 bset_i = isl_set_copy_basic_set(set_i);
240 bset_j = isl_set_copy_basic_set(set_j);
241 cmp = isl_basic_set_compare_at(bset_i, bset_j, level-1);
242 isl_basic_set_free(bset_i);
243 isl_basic_set_free(bset_j);
244 if (!cmp)
245 continue;
246 if (cmp > 0) {
247 follows[i][j] = 1;
248 for (k = 0; k < i; ++k)
249 follows[i][k] |= follows[j][k];
250 } else {
251 follows[j][i] = 1;
252 for (k = 0; k < i; ++k)
253 follows[k][i] |= follows[k][j];
258 for (i = 0, j = 0; i < nb_doms; j = (j + 1) % nb_doms) {
259 for (k = 0; k < nb_doms; ++k)
260 if (follows[j][k])
261 break;
262 if (k < nb_doms)
263 continue;
264 for (k = 0; k < nb_doms; ++k)
265 follows[k][j] = 0;
266 follows[j][j] = 1;
267 permut[i] = 1 + j;
268 ++i;
271 for (i = 0; i < nb_doms; ++i)
272 free(follows[i]);
273 free(follows);
278 * Check whether there is or may be any value of dom1 at the given level
279 * that is greater than or equal to a value of dom2 at the same level.
281 * Return
282 * 1 is there is or may be a greater-than pair.
283 * 0 if there is no greater-than pair, but there may be an equal-to pair
284 * -1 if there is definitely no such pair
286 int cloog_domain_follows(CloogDomain *dom1, CloogDomain *dom2, unsigned level)
288 isl_set *set1 = isl_set_from_cloog_domain(dom1);
289 isl_set *set2 = isl_set_from_cloog_domain(dom2);
290 int follows;
292 follows = isl_set_follows_at(set1, set2, level - 1);
293 assert(follows >= -1);
295 return follows;
300 * cloog_domain_empty function:
301 * Returns an empty domain of the same dimensions as template.
303 CloogDomain *cloog_domain_empty(CloogDomain *template)
305 isl_set *set = isl_set_from_cloog_domain(template);
306 return cloog_domain_from_isl_set(isl_set_empty_like(set));
311 * Return 1 if the specified dimension has both an upper and a lower bound.
313 int cloog_domain_is_bounded(CloogDomain *dom, unsigned level)
315 isl_set *set = isl_set_from_cloog_domain(dom);
316 return isl_set_dim_is_bounded(set, isl_dim_set, level - 1);
320 /******************************************************************************
321 * Structure display function *
322 ******************************************************************************/
326 * cloog_domain_print_structure :
327 * this function is a more human-friendly way to display the CloogDomain data
328 * structure, it only shows the constraint system and includes an indentation
329 * level (level) in order to work with others print_structure functions.
331 void cloog_domain_print_structure(FILE *file, CloogDomain *domain, int level,
332 const char *name)
334 int i ;
335 isl_set *set = isl_set_from_cloog_domain(domain);
337 /* Go to the right level. */
338 for (i = 0; i < level; i++)
339 fprintf(file, "|\t");
341 if (!set) {
342 fprintf(file, "+-- Null CloogDomain\n");
343 return;
345 fprintf(file, "+-- %s\n", name);
346 for (i = 0; i < level+1; ++i)
347 fprintf(file, "|\t");
349 isl_set_print(set, file, 0, ISL_FORMAT_ISL);
351 fprintf(file, "\n");
355 /******************************************************************************
356 * Memory deallocation function *
357 ******************************************************************************/
360 void cloog_domain_list_free(CloogDomainList *list)
362 CloogDomainList *next;
364 for ( ; list; list = next) {
365 next = list->next;
366 cloog_domain_free(list->domain);
367 free(list);
373 * cloog_scattering_list_free function:
374 * This function frees the allocated memory for a CloogScatteringList structure.
376 void cloog_scattering_list_free(CloogScatteringList *list)
378 while (list != NULL) {
379 CloogScatteringList *temp = list->next;
380 isl_map *map = isl_map_from_cloog_scattering(list->scatt);
381 isl_map_free(map);
382 free(list);
383 list = temp;
388 /******************************************************************************
389 * Reading function *
390 ******************************************************************************/
394 * cloog_domain_read_context function:
395 * Read parameter domain.
397 CloogDomain *cloog_domain_read_context(CloogState *state, FILE *input)
399 struct isl_ctx *ctx = state->backend->ctx;
400 isl_set *set;
402 set = isl_set_read_from_file(ctx, input, 0);
403 set = isl_set_move_dims(set, isl_dim_param, 0,
404 isl_dim_set, 0, isl_set_dim(set, isl_dim_set));
406 return cloog_domain_from_isl_set(set);
411 * cloog_domain_from_context
412 * Reinterpret context by turning parameters into variables.
414 CloogDomain *cloog_domain_from_context(CloogDomain *context)
416 isl_set *set = isl_set_from_cloog_domain(context);
418 set = isl_set_move_dims(set, isl_dim_set, 0,
419 isl_dim_param, 0, isl_set_dim(set, isl_dim_param));
421 return cloog_domain_from_isl_set(set);
426 * cloog_domain_union_read function:
427 * This function reads a union of polyhedra into a file (input) and
428 * returns a pointer to a CloogDomain containing the read information.
430 CloogDomain *cloog_domain_union_read(CloogState *state,
431 FILE *input, int nb_parameters)
433 struct isl_ctx *ctx = state->backend->ctx;
434 struct isl_set *set;
436 set = isl_set_read_from_file(ctx, input, nb_parameters);
437 return cloog_domain_from_isl_set(set);
442 * cloog_domain_read_scattering function:
443 * This function reads in a scattering function from the file input.
445 * We try to read the scattering relation as a map, but if it is
446 * specified in the original PolyLib format, then isl_map_read_from_file
447 * will treat the input as a set return a map with zero input dimensions.
448 * In this case, we need to decompose the set into a map from
449 * scattering dimensions to domain dimensions and then invert the
450 * resulting map.
452 CloogScattering *cloog_domain_read_scattering(CloogDomain *domain, FILE *input)
454 isl_set *set = isl_set_from_cloog_domain(domain);
455 isl_ctx *ctx = isl_set_get_ctx(set);
456 struct isl_map *scat;
457 unsigned nparam;
458 unsigned dim;
459 unsigned n_scat;
461 dim = isl_set_dim(set, isl_dim_set);
462 nparam = isl_set_dim(set, isl_dim_param);
463 scat = isl_map_read_from_file(ctx, input, nparam);
464 if (isl_map_dim(scat, isl_dim_in) != dim) {
465 n_scat = isl_map_dim(scat, isl_dim_out) - dim;
466 scat = isl_map_move_dims(scat, isl_dim_in, 0,
467 isl_dim_out, n_scat, dim);
469 return cloog_scattering_from_isl_map(scat);
472 /******************************************************************************
473 * CloogMatrix Reading function *
474 ******************************************************************************/
477 * isl_constraint_read_from_matrix:
478 * Convert a single line of a matrix to a isl_constraint.
479 * Returns a pointer to the constraint if successful; NULL otherwise.
481 static struct isl_constraint *isl_constraint_read_from_matrix(
482 struct isl_dim *dim, cloog_int_t *row)
484 struct isl_constraint *constraint;
485 int j;
486 int nvariables = isl_dim_size(dim, isl_dim_set);
487 int nparam = isl_dim_size(dim, isl_dim_param);
489 if (cloog_int_is_zero(row[0]))
490 constraint = isl_equality_alloc(dim);
491 else
492 constraint = isl_inequality_alloc(dim);
494 for (j = 0; j < nvariables; ++j)
495 isl_constraint_set_coefficient(constraint, isl_dim_out, j,
496 row[1 + j]);
498 for (j = 0; j < nparam; ++j)
499 isl_constraint_set_coefficient(constraint, isl_dim_param, j,
500 row[1 + nvariables + j]);
502 isl_constraint_set_constant(constraint, row[1 + nvariables + nparam]);
504 return constraint;
508 * isl_basic_set_read_from_matrix:
509 * Convert matrix to basic_set. The matrix contains nparam parameter columns.
510 * Returns a pointer to the basic_set if successful; NULL otherwise.
512 static struct isl_basic_set *isl_basic_set_read_from_matrix(struct isl_ctx *ctx,
513 CloogMatrix* matrix, int nparam)
515 struct isl_dim *dim;
516 struct isl_basic_set *bset;
517 int i;
518 unsigned nrows, ncolumns;
520 nrows = matrix->NbRows;
521 ncolumns = matrix->NbColumns;
522 int nvariables = ncolumns - 2 - nparam;
524 dim = isl_dim_set_alloc(ctx, nparam, nvariables);
526 bset = isl_basic_set_universe(isl_dim_copy(dim));
528 for (i = 0; i < nrows; ++i) {
529 cloog_int_t *row = matrix->p[i];
530 struct isl_constraint *constraint =
531 isl_constraint_read_from_matrix(isl_dim_copy(dim), row);
532 bset = isl_basic_set_add_constraint(bset, constraint);
535 isl_dim_free(dim);
537 return bset;
541 * cloog_domain_from_cloog_matrix:
542 * Create a CloogDomain containing the constraints described in matrix.
543 * nparam is the number of parameters contained in the domain.
544 * Returns a pointer to the CloogDomain if successful; NULL otherwise.
546 CloogDomain *cloog_domain_from_cloog_matrix(CloogState *state,
547 CloogMatrix *matrix, int nparam)
549 struct isl_ctx *ctx = state->backend->ctx;
550 struct isl_basic_set *bset;
552 bset = isl_basic_set_read_from_matrix(ctx, matrix, nparam);
554 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
558 * cloog_scattering_from_cloog_matrix:
559 * Create a CloogScattering containing the constraints described in matrix.
560 * nparam is the number of parameters contained in the domain.
561 * Returns a pointer to the CloogScattering if successful; NULL otherwise.
563 CloogScattering *cloog_scattering_from_cloog_matrix(CloogState *state,
564 CloogMatrix *matrix, int nb_scat, int nb_par)
566 struct isl_ctx *ctx = state->backend->ctx;
567 struct isl_basic_set *bset;
568 struct isl_basic_map *scat;
569 struct isl_dim *dims;
570 unsigned dim;
572 bset = isl_basic_set_read_from_matrix(ctx, matrix, nb_par);
573 dim = isl_basic_set_n_dim(bset) - nb_scat;
574 dims = isl_dim_alloc(ctx, nb_par, nb_scat, dim);
576 scat = isl_basic_map_from_basic_set(bset, dims);
577 scat = isl_basic_map_reverse(scat);
578 return cloog_scattering_from_isl_map(isl_map_from_basic_map(scat));
582 /******************************************************************************
583 * Processing functions *
584 ******************************************************************************/
589 * cloog_domain_isempty function:
591 int cloog_domain_isempty(CloogDomain *domain)
593 isl_set *set = isl_set_from_cloog_domain(domain);
594 return isl_set_is_empty(set);
599 * cloog_domain_universe function:
600 * This function returns the complete dim-dimensional space.
602 CloogDomain *cloog_domain_universe(CloogState *state, unsigned dim)
604 struct isl_dim *dims;
605 struct isl_basic_set *bset;
607 dims = isl_dim_set_alloc(state->backend->ctx, 0, dim);
608 bset = isl_basic_set_universe(dims);
609 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
614 * cloog_domain_project function:
615 * This function returns the projection of
616 * (domain) on the (level) first dimensions (i.e. outer loops).
618 CloogDomain *cloog_domain_project(CloogDomain *domain, int level)
620 isl_set *set = isl_set_from_cloog_domain(domain);
621 set = isl_set_remove_dims(isl_set_copy(set), isl_dim_set,
622 level, isl_set_n_dim(set) - level);
623 set = isl_set_compute_divs(set);
624 if (level > 0)
625 set = isl_set_remove_divs_involving_dims(set,
626 isl_dim_set, level - 1, 1);
627 return cloog_domain_from_isl_set(set);
632 * cloog_domain_extend function:
633 * This function returns the (domain) given as input with (dim)
634 * dimensions and (nb_par) parameters.
635 * This function does not free (domain), and returns a new CloogDomain.
637 CloogDomain *cloog_domain_extend(CloogDomain *domain, int dim)
639 isl_set *set = isl_set_from_cloog_domain(domain);
640 set = isl_set_extend(isl_set_copy(set), isl_set_n_param(set), dim);
641 return cloog_domain_from_isl_set(set);
646 * cloog_domain_never_integral function:
647 * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0.
648 * There is no need to check for such constraints explicitly for the isl
649 * backend.
651 int cloog_domain_never_integral(CloogDomain * domain)
653 isl_set *set = isl_set_from_cloog_domain(domain);
654 return isl_set_is_empty(set);
659 * Check whether the loop at "level" is executed at most once.
660 * We construct a map that maps all remaining variables to this iterator
661 * and check whether this map is single valued.
663 * Alternatively, we could have mapped the domain through a mapping
664 * [p] -> { [..., i] -> [..., i'] : i' > i }
665 * and then taken the intersection of the original domain and the transformed
666 * domain. If this intersection is empty, then the corresponding
667 * loop is executed at most once.
669 int cloog_domain_is_otl(CloogDomain *domain, int level)
671 int otl;
672 isl_set *set = isl_set_from_cloog_domain(domain);
673 isl_map *map;
675 map = isl_map_from_domain(isl_set_copy(set));
676 map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_in, level - 1, 1);
677 otl = isl_map_is_single_valued(map);
678 isl_map_free(map);
680 return otl;
685 * cloog_domain_stride function:
686 * This function finds the stride imposed to unknown with the column number
687 * 'strided_level' in order to be integral. For instance, if we have a
688 * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral
689 * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to
690 * the unknown i. The function returns the imposed stride in a parameter field.
691 * - domain is the set of constraint we have to consider,
692 * - strided_level is the column number of the unknown for which a stride have
693 * to be found,
694 * - looking_level is the column number of the unknown that impose a stride to
695 * the first unknown.
696 * - stride is the stride that is returned back as a function parameter.
697 * - offset is the value of the constant c if the condition is of the shape
698 * (i + c)%s = 0, s being the stride.
700 void cloog_domain_stride(CloogDomain *domain, int strided_level,
701 cloog_int_t *stride, cloog_int_t *offset)
703 isl_set *set = isl_set_from_cloog_domain(domain);
704 isl_set_dim_residue_class(set, strided_level - 1, stride, offset);
705 if (!isl_int_is_zero(*offset))
706 isl_int_sub(*offset, *stride, *offset);
707 return;
711 struct cloog_can_stride {
712 int level;
713 int can_stride;
716 static int constraint_can_stride(__isl_take isl_constraint *c, void *user)
718 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
719 int i;
720 isl_int v;
721 unsigned n_div;
723 isl_int_init(v);
724 isl_constraint_get_coefficient(c, isl_dim_set, ccs->level - 1, &v);
725 if (isl_int_is_pos(v)) {
726 n_div = isl_constraint_dim(c, isl_dim_div);
727 for (i = 0; i < n_div; ++i) {
728 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
729 if (!isl_int_is_zero(v))
730 break;
732 if (i < n_div)
733 ccs->can_stride = 0;
735 isl_int_clear(v);
736 isl_constraint_free(c);
738 return 0;
741 static int basic_set_can_stride(__isl_take isl_basic_set *bset, void *user)
743 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
744 int r;
746 r = isl_basic_set_foreach_constraint(bset, constraint_can_stride, ccs);
747 isl_basic_set_free(bset);
748 return r;
753 * Return 1 if CLooG is allowed to perform stride detection on level "level"
754 * and 0 otherwise.
755 * Currently, stride detection is only allowed when none of the lower
756 * bound constraints involve any existentially quantified variables.
757 * The reason is that the current isl interface does not make it
758 * easy to construct an integer division that depends on other integer
759 * divisions.
760 * By not allowing existentially quantified variables in the constraints,
761 * we can ignore them in cloog_domain_stride_lower_bound.
763 int cloog_domain_can_stride(CloogDomain *domain, int level)
765 struct cloog_can_stride ccs = { level, 1 };
766 isl_set *set = isl_set_from_cloog_domain(domain);
767 int r;
768 r = isl_set_foreach_basic_set(set, basic_set_can_stride, &ccs);
769 assert(r == 0);
770 return ccs.can_stride;
774 struct cloog_stride_lower {
775 int level;
776 CloogStride *stride;
777 isl_set *set;
778 isl_basic_set *bounds;
781 /* If the given constraint is a lower bound on csl->level, then add
782 * a lower bound to csl->bounds that makes sure that the remainder
783 * of the smallest value on division by csl->stride is equal to csl->offset.
785 * In particular, the given lower bound is of the form
787 * a i + f >= 0
789 * where f may depend on the parameters and other iterators.
790 * The stride is s and the offset is d.
791 * The lower bound -f/a may not satisfy the above condition. In fact,
792 * it may not even be integral. We want to round this value of i up
793 * to the nearest value that satisfies the condition and add the corresponding
794 * lower bound constraint. This nearest value is obtained by rounding
795 * i - d up to the nearest multiple of s.
796 * That is, we first subtract d
798 * i' = -f/a - d
800 * then we round up to the nearest multiple of s
802 * i'' = s * ceil(i'/s)
804 * and finally, we add d again
806 * i''' = i'' + d
808 * and impose the constraint i >= i'''.
810 * We find
812 * i'' = s * ceil((-f - a * d)/(a * s)) = - s * floor((f + a * d)/(a * s))
814 * i >= - s * floor((f + a * d)/(a * s)) + d
816 * or
817 * i + s * floor((f + a * d)/(a * s)) - d >= 0
819 static int constraint_stride_lower(__isl_take isl_constraint *c, void *user)
821 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
822 int i;
823 isl_int v;
824 isl_int t;
825 isl_constraint *bound;
826 isl_div *div;
827 int pos;
828 unsigned nparam, nvar;
830 isl_int_init(v);
831 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
832 if (!isl_int_is_pos(v)) {
833 isl_int_clear(v);
834 isl_constraint_free(c);
836 return 0;
839 isl_int_init(t);
841 nparam = isl_constraint_dim(c, isl_dim_param);
842 nvar = isl_constraint_dim(c, isl_dim_set);
843 bound = isl_inequality_alloc(isl_basic_set_get_dim(csl->bounds));
844 div = isl_div_alloc(isl_basic_set_get_dim(csl->bounds));
845 isl_int_mul(t, v, csl->stride->stride);
846 isl_div_set_denominator(div, t);
847 for (i = 0; i < nparam; ++i) {
848 isl_constraint_get_coefficient(c, isl_dim_param, i, &t);
849 isl_div_set_coefficient(div, isl_dim_param, i, t);
851 for (i = 0; i < nvar; ++i) {
852 if (i == csl->level - 1)
853 continue;
854 isl_constraint_get_coefficient(c, isl_dim_set, i, &t);
855 isl_div_set_coefficient(div, isl_dim_set, i, t);
857 isl_constraint_get_constant(c, &t);
858 isl_int_addmul(t, v, csl->stride->offset);
859 isl_div_set_constant(div, t);
861 bound = isl_constraint_add_div(bound, div, &pos);
862 isl_int_set_si(t, 1);
863 isl_constraint_set_coefficient(bound, isl_dim_set,
864 csl->level - 1, t);
865 isl_constraint_set_coefficient(bound, isl_dim_div, pos,
866 csl->stride->stride);
867 isl_int_neg(t, csl->stride->offset);
868 isl_constraint_set_constant(bound, t);
869 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
871 isl_int_clear(v);
872 isl_int_clear(t);
873 isl_constraint_free(c);
875 return 0;
878 /* This functions performs essentially the same operation as
879 * constraint_stride_lower, the only difference being that the offset d
880 * is not a constant, but an affine expression in terms of the parameters
881 * and earlier variables. In particular the affine expression is equal
882 * to the coefficients of stride->constraint multiplied by stride->factor.
883 * As in constraint_stride_lower, we add an extra bound
885 * i + s * floor((f + a * d)/(a * s)) - d >= 0
887 * for each lower bound
889 * a i + f >= 0
891 * where d is not the aforementioned affine expression.
893 static int constraint_stride_lower_c(__isl_take isl_constraint *c, void *user)
895 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
896 int i;
897 isl_int v;
898 isl_int t, u;
899 isl_constraint *bound;
900 isl_constraint *csl_c;
901 isl_div *div;
902 int pos;
903 unsigned nparam, nvar;
905 isl_int_init(v);
906 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
907 if (!isl_int_is_pos(v)) {
908 isl_int_clear(v);
909 isl_constraint_free(c);
911 return 0;
914 csl_c = &csl->stride->constraint->isl;
916 isl_int_init(t);
917 isl_int_init(u);
919 nparam = isl_constraint_dim(c, isl_dim_param);
920 nvar = isl_constraint_dim(c, isl_dim_set);
921 bound = isl_inequality_alloc(isl_basic_set_get_dim(csl->bounds));
922 div = isl_div_alloc(isl_basic_set_get_dim(csl->bounds));
923 isl_int_mul(t, v, csl->stride->stride);
924 isl_div_set_denominator(div, t);
925 for (i = 0; i < nparam; ++i) {
926 isl_constraint_get_coefficient(c, isl_dim_param, i, &t);
927 isl_constraint_get_coefficient(csl_c, isl_dim_param, i, &u);
928 isl_int_mul(u, u, csl->stride->factor);
929 isl_int_addmul(t, v, u);
930 isl_div_set_coefficient(div, isl_dim_param, i, t);
931 isl_int_neg(u, u);
932 isl_constraint_set_coefficient(bound, isl_dim_param, i, u);
934 for (i = 0; i < nvar; ++i) {
935 if (i == csl->level - 1)
936 continue;
937 isl_constraint_get_coefficient(c, isl_dim_set, i, &t);
938 isl_constraint_get_coefficient(csl_c, isl_dim_set, i, &u);
939 isl_int_mul(u, u, csl->stride->factor);
940 isl_int_addmul(t, v, u);
941 isl_div_set_coefficient(div, isl_dim_set, i, t);
942 isl_int_neg(u, u);
943 isl_constraint_set_coefficient(bound, isl_dim_set, i, u);
945 isl_constraint_get_constant(c, &t);
946 isl_constraint_get_constant(csl_c, &u);
947 isl_int_mul(u, u, csl->stride->factor);
948 isl_int_addmul(t, v, u);
949 isl_div_set_constant(div, t);
950 isl_int_neg(u, u);
951 isl_constraint_set_constant(bound, u);
953 bound = isl_constraint_add_div(bound, div, &pos);
954 isl_int_set_si(t, 1);
955 isl_constraint_set_coefficient(bound, isl_dim_set,
956 csl->level - 1, t);
957 isl_constraint_set_coefficient(bound, isl_dim_div, pos,
958 csl->stride->stride);
959 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
961 isl_int_clear(u);
962 isl_int_clear(t);
963 isl_int_clear(v);
964 isl_constraint_free(c);
966 return 0;
969 static int basic_set_stride_lower(__isl_take isl_basic_set *bset, void *user)
971 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
972 int r;
974 csl->bounds = isl_basic_set_universe_like(bset);
975 if (csl->stride->constraint)
976 r = isl_basic_set_foreach_constraint(bset,
977 &constraint_stride_lower_c, csl);
978 else
979 r = isl_basic_set_foreach_constraint(bset,
980 &constraint_stride_lower, csl);
981 bset = isl_basic_set_intersect(bset, csl->bounds);
982 csl->set = isl_set_union(csl->set, isl_set_from_basic_set(bset));
984 return r;
988 * Update the lower bounds at level "level" to the given stride information.
989 * That is, make sure that the remainder on division by "stride"
990 * is equal to "offset".
992 CloogDomain *cloog_domain_stride_lower_bound(CloogDomain *domain, int level,
993 CloogStride *stride)
995 struct cloog_stride_lower csl;
996 isl_set *set = isl_set_from_cloog_domain(domain);
997 int r;
999 csl.stride = stride;
1000 csl.level = level;
1001 csl.set = isl_set_empty_like(set);
1003 r = isl_set_foreach_basic_set(set, basic_set_stride_lower, &csl);
1004 assert(r == 0);
1006 cloog_domain_free(domain);
1007 return cloog_domain_from_isl_set(csl.set);
1012 * cloog_domain_lazy_equal function:
1013 * This function returns 1 if the domains given as input are the same, 0 if it
1014 * is unable to decide.
1016 int cloog_domain_lazy_equal(CloogDomain *d1, CloogDomain *d2)
1018 isl_set *set1 = isl_set_from_cloog_domain(d1);
1019 isl_set *set2 = isl_set_from_cloog_domain(d2);
1020 return isl_set_fast_is_equal(set1, set2);
1023 struct cloog_bound_split {
1024 isl_set *set;
1025 int level;
1026 int lower;
1027 int upper;
1030 static int constraint_bound_split(__isl_take isl_constraint *c, void *user)
1032 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1033 isl_int v;
1034 int i;
1035 int handle = 0;
1037 isl_int_init(v);
1038 isl_constraint_get_coefficient(c, isl_dim_set, cbs->level - 1, &v);
1039 if (!cbs->lower && isl_int_is_pos(v))
1040 cbs->lower = handle = 1;
1041 else if (!cbs->upper && isl_int_is_neg(v))
1042 cbs->upper = handle = 1;
1043 if (handle) {
1044 for (i = 0; i < isl_set_dim(cbs->set, isl_dim_param); ++i) {
1045 isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
1046 if (isl_int_is_zero(v))
1047 continue;
1048 cbs->set = isl_set_split_dims(cbs->set,
1049 isl_dim_param, i, 1);
1052 isl_int_clear(v);
1053 isl_constraint_free(c);
1055 return (cbs->lower && cbs->upper) ? -1 : 0;
1058 static int basic_set_bound_split(__isl_take isl_basic_set *bset, void *user)
1060 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1061 int r;
1063 cbs->lower = 0;
1064 cbs->upper = 0;
1065 r = isl_basic_set_foreach_constraint(bset, constraint_bound_split, cbs);
1066 isl_basic_set_free(bset);
1067 return ((!cbs->lower || !cbs->upper) && r < 0) ? -1 : 0;
1071 * Return a union of sets S_i such that the convex hull of "dom",
1072 * when intersected with one the sets S_i, will have an upper and
1073 * lower bound for the dimension at "level" (provided "dom" itself
1074 * has such bounds for the dimensions).
1076 * We currently take a very simple approach. For each of the basic
1077 * sets in "dom" we pick a lower and an upper bound and split the
1078 * range of any parameter involved in these two bounds in a
1079 * nonnegative and a negative part. This ensures that the symbolic
1080 * constant in these two constraints are themselves bounded and
1081 * so there will be at least one upper and one lower bound
1082 * in the convex hull.
1084 CloogDomain *cloog_domain_bound_splitter(CloogDomain *dom, int level)
1086 struct cloog_bound_split cbs;
1087 isl_set *set = isl_set_from_cloog_domain(dom);
1088 int r;
1089 cbs.level = level;
1090 cbs.set = isl_set_universe_like(set);
1091 r = isl_set_foreach_basic_set(set, basic_set_bound_split, &cbs);
1092 assert(r == 0);
1093 return cloog_domain_from_isl_set(cbs.set);
1098 * cloog_scattering_lazy_block function:
1099 * This function returns 1 if the two scattering functions s1 and s2 given
1100 * as input are the same (except possibly for the final dimension, where we
1101 * allow a difference of 1), assuming that the domains on which this
1102 * scatterings are applied are the same.
1103 * In fact this function answers the question "can I
1104 * safely consider the two domains as only one with two statements (a block) ?".
1105 * - s1 and s2 are the two domains to check for blocking,
1106 * - scattering is the linked list of all domains,
1107 * - scattdims is the total number of scattering dimentions.
1109 int cloog_scattering_lazy_block(CloogScattering *s1, CloogScattering *s2,
1110 CloogScatteringList *scattering, int scattdims)
1112 int i;
1113 struct isl_dim *dim;
1114 struct isl_map *rel;
1115 struct isl_set *delta;
1116 isl_map *map1 = isl_map_from_cloog_scattering(s1);
1117 isl_map *map2 = isl_map_from_cloog_scattering(s2);
1118 int fixed, block;
1119 isl_int cst;
1120 unsigned n_scat;
1122 n_scat = isl_map_dim(map1, isl_dim_out);
1123 if (n_scat != isl_map_dim(map2, isl_dim_out))
1124 return 0;
1126 dim = isl_map_get_dim(map1);
1127 dim = isl_dim_map_from_set(isl_dim_domain(dim));
1128 rel = isl_map_identity(dim);
1129 rel = isl_map_apply_domain(rel, isl_map_copy(map1));
1130 rel = isl_map_apply_range(rel, isl_map_copy(map2));
1131 delta = isl_map_deltas(rel);
1132 isl_int_init(cst);
1133 for (i = 0; i < n_scat; ++i) {
1134 fixed = isl_set_fast_dim_is_fixed(delta, i, &cst);
1135 if (fixed != 1)
1136 break;
1137 if (i+1 < n_scat && !isl_int_is_zero(cst))
1138 break;
1139 if (!isl_int_is_zero(cst) && !isl_int_is_one(cst))
1140 break;
1142 block = i >= n_scat;
1143 isl_int_clear(cst);
1144 isl_set_free(delta);
1145 return block;
1150 * cloog_domain_lazy_disjoint function:
1151 * This function returns 1 if the domains given as input are disjoint, 0 if it
1152 * is unable to decide.
1154 int cloog_domain_lazy_disjoint(CloogDomain *d1, CloogDomain *d2)
1156 isl_set *set1 = isl_set_from_cloog_domain(d1);
1157 isl_set *set2 = isl_set_from_cloog_domain(d2);
1158 return isl_set_fast_is_disjoint(set1, set2);
1163 * cloog_scattering_list_lazy_same function:
1164 * This function returns 1 if two domains in the list are the same, 0 if it
1165 * is unable to decide.
1167 int cloog_scattering_list_lazy_same(CloogScatteringList *list)
1169 CloogScatteringList *one, *other;
1170 isl_map *one_map, *other_map;
1172 for (one = list; one; one = one->next) {
1173 one_map = isl_map_from_cloog_scattering(one->scatt);
1174 for (other = one->next; other; other = other->next) {
1175 other_map = isl_map_from_cloog_scattering(other->scatt);
1176 if (isl_map_fast_is_equal(one_map, other_map))
1177 return 1;
1180 return 0;
1183 int cloog_domain_dimension(CloogDomain * domain)
1185 isl_set *set = isl_set_from_cloog_domain(domain);
1186 return isl_set_dim(set, isl_dim_set);
1189 int cloog_domain_parameter_dimension(CloogDomain *domain)
1191 isl_set *set = isl_set_from_cloog_domain(domain);
1192 return isl_set_dim(set, isl_dim_param);
1195 int cloog_scattering_dimension(CloogScattering *scatt, CloogDomain *domain)
1197 isl_map *map = isl_map_from_cloog_scattering(scatt);
1198 return isl_map_dim(map, isl_dim_out);
1201 int cloog_domain_isconvex(CloogDomain * domain)
1203 isl_set *set = isl_set_from_cloog_domain(domain);
1204 return isl_set_n_basic_set(set) <= 1;
1209 * cloog_domain_cut_first function:
1210 * This function splits off and returns the first convex set in the
1211 * union "domain". The remainder of the union is returned in rest.
1212 * The original "domain" itself is destroyed and may not be used
1213 * after a call to this function.
1215 CloogDomain *cloog_domain_cut_first(CloogDomain *domain, CloogDomain **rest)
1217 isl_set *set = isl_set_from_cloog_domain(domain);
1218 struct isl_basic_set *first;
1220 first = isl_set_copy_basic_set(set);
1221 set = isl_set_drop_basic_set(set, first);
1222 *rest = cloog_domain_from_isl_set(set);
1224 return cloog_domain_from_isl_set(isl_set_from_basic_set(first));
1229 * Given a union domain, try to find a simpler representation
1230 * using fewer sets in the union.
1231 * The original "domain" itself is destroyed and may not be used
1232 * after a call to this function.
1234 CloogDomain *cloog_domain_simplify_union(CloogDomain *domain)
1236 isl_set *set = isl_set_from_cloog_domain(domain);
1237 return cloog_domain_from_isl_set(isl_set_coalesce(set));
1242 * cloog_scattering_lazy_isscalar function:
1243 * this function returns 1 if the scattering dimension 'dimension' in the
1244 * scattering 'scatt' is constant.
1245 * If value is not NULL, then it is set to the constant value of dimension.
1247 int cloog_scattering_lazy_isscalar(CloogScattering *scatt, int dimension,
1248 cloog_int_t *value)
1250 isl_map *map = isl_map_from_cloog_scattering(scatt);
1251 return isl_map_fast_is_fixed(map, isl_dim_out, dimension, value);
1256 * cloog_domain_lazy_isconstant function:
1257 * this function returns 1 if the dimension 'dimension' in the
1258 * domain 'domain' is constant.
1259 * If value is not NULL, then it is set to the constant value of dimension.
1261 int cloog_domain_lazy_isconstant(CloogDomain *domain, int dimension,
1262 cloog_int_t *value)
1264 isl_set *set = isl_set_from_cloog_domain(domain);
1265 return isl_set_fast_dim_is_fixed(set, dimension, value);
1270 * cloog_scattering_erase_dimension function:
1271 * this function returns a CloogDomain structure builds from 'domain' where
1272 * we removed the dimension 'dimension' and every constraint involving this
1273 * dimension.
1275 CloogScattering *cloog_scattering_erase_dimension(CloogScattering *scattering,
1276 int dimension)
1278 isl_map *map = isl_map_from_cloog_scattering(scattering);
1279 map = isl_map_remove_dims(isl_map_copy(map), isl_dim_out, dimension, 1);
1280 return cloog_scattering_from_isl_map(map);
1284 * cloog_domain_cube:
1285 * Construct and return a dim-dimensional cube, with values ranging
1286 * between min and max in each dimension.
1288 CloogDomain *cloog_domain_cube(CloogState *state,
1289 int dim, cloog_int_t min, cloog_int_t max)
1291 int i;
1292 struct isl_basic_set *cube;
1293 struct isl_basic_set *interval;
1294 struct isl_basic_set_list *list;
1296 if (dim == 0)
1297 return cloog_domain_universe(state, dim);
1299 interval = isl_basic_set_interval(state->backend->ctx, min, max);
1300 list = isl_basic_set_list_alloc(state->backend->ctx, dim);
1301 for (i = 0; i < dim; ++i)
1302 list = isl_basic_set_list_add(list, isl_basic_set_copy(interval));
1303 isl_basic_set_free(interval);
1304 cube = isl_basic_set_list_product(list);
1305 return cloog_domain_from_isl_set(isl_set_from_basic_set(cube));
1310 * cloog_domain_scatter function:
1311 * This function add the scattering (scheduling) informations to a domain.
1313 CloogDomain *cloog_domain_scatter(CloogDomain *domain, CloogScattering *scatt)
1315 isl_set *set = isl_set_from_cloog_domain(domain);
1316 isl_map *map = isl_map_from_cloog_scattering(scatt);
1318 map = isl_map_reverse(isl_map_copy(map));
1319 map = isl_map_intersect_range(map, set);
1320 set = isl_set_flatten(isl_map_wrap(map));
1321 return cloog_domain_from_isl_set(set);
1324 static int add_domain_from_map(__isl_take isl_map *map, void *user)
1326 isl_dim *dim;
1327 const char *name;
1328 CloogDomain *domain;
1329 CloogScattering *scat;
1330 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1332 dim = isl_map_get_dim(map);
1333 name = isl_dim_get_tuple_name(dim, isl_dim_in);
1334 domain = cloog_domain_from_isl_set(isl_map_domain(isl_map_copy(map)));
1335 scat = cloog_scattering_from_isl_map(map);
1336 *ud = cloog_union_domain_add_domain(*ud, name, domain, scat, NULL);
1337 isl_dim_free(dim);
1339 return 0;
1343 * Construct a CloogUnionDomain from an isl_union_map representing
1344 * a global scattering function. The input is a mapping from different
1345 * spaces (different tuple names and possibly different dimensions)
1346 * to a common space. The iteration domains are set to the domains
1347 * in each space. The statement names are set to the names of the
1348 * spaces. The parameter names of the result are set to those of
1349 * the input, but the iterator and scattering dimension names are
1350 * left unspecified.
1352 CloogUnionDomain *cloog_union_domain_from_isl_union_map(
1353 __isl_take isl_union_map *umap)
1355 int i;
1356 int nparam;
1357 isl_dim *dim;
1358 CloogUnionDomain *ud;
1360 dim = isl_union_map_get_dim(umap);
1361 nparam = isl_dim_size(dim, isl_dim_param);
1363 ud = cloog_union_domain_alloc(nparam);
1365 for (i = 0; i < nparam; ++i) {
1366 const char *s = isl_dim_get_name(dim, isl_dim_param, i);
1367 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1369 isl_dim_free(dim);
1371 if (isl_union_map_foreach_map(umap, &add_domain_from_map, &ud) < 0) {
1372 isl_union_map_free(umap);
1373 cloog_union_domain_free(ud);
1374 assert(0);
1377 isl_union_map_free(umap);
1379 return ud;
1382 static int count_same_name(__isl_keep isl_dim *dim,
1383 enum isl_dim_type type, unsigned pos, const char *name)
1385 enum isl_dim_type t;
1386 unsigned p, s;
1387 int count = 0;
1388 int len = strlen(name);
1390 for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) {
1391 s = t == type ? pos : isl_dim_size(dim, t);
1392 for (p = 0; p < s; ++p) {
1393 const char *n = isl_dim_get_name(dim, t, p);
1394 if (n && !strncmp(n, name, len))
1395 count++;
1398 return count;
1401 static int add_domain(__isl_take isl_set *set, void *user)
1403 int i, nvar;
1404 isl_ctx *ctx;
1405 isl_dim *dim;
1406 char buffer[20];
1407 const char *name;
1408 CloogDomain *domain;
1409 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1411 ctx = isl_set_get_ctx(set);
1412 dim = isl_set_get_dim(set);
1413 name = isl_dim_get_tuple_name(dim, isl_dim_set);
1414 set = isl_set_flatten(set);
1415 set = isl_set_set_tuple_name(set, NULL);
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;