isl backend: cloog_domain_project: avoid use of undocumented isl_set_extend
[cloog.git] / source / isl / domain.c
blobc8fcb978fa9b29638cd1a3103f615f37ba64cec2
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <cloog/isl/cloog.h>
7 #include <isl/list.h>
8 #include <isl/constraint.h>
9 #include <isl/div.h>
10 #include <isl/ilp.h>
11 #include <isl/aff.h>
13 CloogDomain *cloog_domain_from_isl_set(struct isl_set *set)
15 set = isl_set_detect_equalities(set);
16 set = isl_set_compute_divs(set);
17 return (CloogDomain *)set;
20 __isl_give isl_set *isl_set_from_cloog_domain(CloogDomain *domain)
22 return (isl_set *)domain;
25 CloogScattering *cloog_scattering_from_isl_map(struct isl_map *map)
27 return (CloogScattering *)map;
30 __isl_give isl_map *isl_map_from_cloog_scattering(CloogScattering *scattering)
32 return (isl_map *)scattering;
36 /**
37 * Returns true if each scattering dimension is defined in terms
38 * of the original iterators.
40 int cloog_scattering_fully_specified(CloogScattering *scattering,
41 CloogDomain *domain)
43 isl_map *map = isl_map_from_cloog_scattering(scattering);
44 return isl_map_is_single_valued(map);
48 CloogConstraintSet *cloog_domain_constraints(CloogDomain *domain)
50 isl_basic_set *bset;
51 isl_set *set = isl_set_from_cloog_domain(domain);
52 assert(isl_set_n_basic_set(set) == 1);
53 bset = isl_set_copy_basic_set(set);
54 return cloog_constraint_set_from_isl_basic_set(bset);
58 void cloog_domain_print_constraints(FILE *foo, CloogDomain *domain,
59 int print_number)
61 isl_basic_set *bset;
62 isl_set *set = isl_set_from_cloog_domain(domain);
64 if (print_number)
65 isl_set_print(set, foo, 0, ISL_FORMAT_EXT_POLYLIB);
66 else {
67 assert(isl_set_n_basic_set(set) == 1);
68 bset = isl_set_copy_basic_set(set);
69 isl_basic_set_print(bset, foo,
70 0, NULL, NULL, ISL_FORMAT_POLYLIB);
71 isl_basic_set_free(bset);
76 void cloog_scattering_print_constraints(FILE *foo, CloogScattering *scattering)
78 isl_map *map = isl_map_from_cloog_scattering(scattering);
79 isl_map_print(map, foo, 0, ISL_FORMAT_EXT_POLYLIB);
83 void cloog_domain_free(CloogDomain * domain)
85 isl_set *set = isl_set_from_cloog_domain(domain);
86 isl_set_free(set);
90 void cloog_scattering_free(CloogScattering *scatt)
92 isl_map *map = isl_map_from_cloog_scattering(scatt);
93 isl_map_free(map);
97 CloogDomain * cloog_domain_copy(CloogDomain * domain)
99 isl_set *set = isl_set_from_cloog_domain(domain);
100 return cloog_domain_from_isl_set(isl_set_copy(set));
105 * cloog_domain_convex function:
106 * Computes the convex hull of domain.
108 CloogDomain *cloog_domain_convex(CloogDomain *domain)
110 isl_set *set = isl_set_from_cloog_domain(domain);
111 set = isl_set_from_basic_set(isl_set_convex_hull(isl_set_copy(set)));
112 return cloog_domain_from_isl_set(set);
117 * cloog_domain_simple_convex:
118 * Given a list (union) of polyhedra, this function returns a "simple"
119 * convex hull of this union. In particular, the constraints of the
120 * the returned polyhedron consist of (parametric) lower and upper
121 * bounds on individual variables and constraints that appear in the
122 * original polyhedra.
124 CloogDomain *cloog_domain_simple_convex(CloogDomain *domain)
126 struct isl_basic_set *hull;
127 isl_set *set = isl_set_from_cloog_domain(domain);
129 if (cloog_domain_isconvex(domain))
130 return cloog_domain_copy(domain);
132 hull = isl_set_bounded_simple_hull(isl_set_copy(set));
133 return cloog_domain_from_isl_set(isl_set_from_basic_set(hull));
138 * cloog_domain_simplify function:
139 * Given two polyhedral domains (dom1) and (dom2),
140 * this function finds the largest domain set (or the smallest list
141 * of non-redundant constraints), that when intersected with polyhedral
142 * domain (dom2) equals (dom1)intersect(dom2). The output is a new CloogDomain
143 * structure with a polyhedral domain with the "redundant" constraints removed.
144 * NB: the second domain is required not to be a union.
146 CloogDomain *cloog_domain_simplify(CloogDomain *dom1, CloogDomain *dom2)
148 isl_set *set1 = isl_set_from_cloog_domain(dom1);
149 isl_set *set2 = isl_set_from_cloog_domain(dom2);
150 set1 = isl_set_gist(isl_set_copy(set1), isl_set_copy(set2));
151 return cloog_domain_from_isl_set(set1);
156 * cloog_domain_union function:
157 * This function returns a new polyhedral domain which is the union of
158 * two polyhedral domains (dom1) U (dom2).
159 * Frees dom1 and dom2;
161 CloogDomain *cloog_domain_union(CloogDomain *dom1, CloogDomain *dom2)
163 isl_set *set1 = isl_set_from_cloog_domain(dom1);
164 isl_set *set2 = isl_set_from_cloog_domain(dom2);
165 set1 = isl_set_union(set1, set2);
166 return cloog_domain_from_isl_set(set1);
172 * cloog_domain_intersection function:
173 * This function returns a new polyhedral domain which is the intersection of
174 * two polyhedral domains (dom1) \cap (dom2).
176 CloogDomain *cloog_domain_intersection(CloogDomain *dom1, CloogDomain *dom2)
178 isl_set *set1 = isl_set_from_cloog_domain(dom1);
179 isl_set *set2 = isl_set_from_cloog_domain(dom2);
180 set1 = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
181 return cloog_domain_from_isl_set(set1);
186 * cloog_domain_difference function:
187 * Returns the set difference domain \ minus.
189 CloogDomain *cloog_domain_difference(CloogDomain *domain, CloogDomain *minus)
191 isl_set *set1 = isl_set_from_cloog_domain(domain);
192 isl_set *set2 = isl_set_from_cloog_domain(minus);
193 set1 = isl_set_subtract(isl_set_copy(set1), isl_set_copy(set2));
194 return cloog_domain_from_isl_set(set1);
199 * cloog_domain_sort function:
200 * This function topologically sorts (nb_doms) domains. Here (doms) is an
201 * array of pointers to CloogDomains, (nb_doms) is the number of domains,
202 * (level) is the level to consider for partial ordering (nb_par) is the
203 * parameter space dimension, (permut) if not NULL, is an array of (nb_doms)
204 * integers that contains a permutation specification after call in order to
205 * apply the topological sorting.
207 void cloog_domain_sort(CloogDomain **doms, unsigned nb_doms, unsigned level,
208 int *permut)
210 int i, j, k, cmp;
211 struct isl_ctx *ctx;
212 unsigned char **follows;
213 isl_set *set_i, *set_j;
214 isl_basic_set *bset_i, *bset_j;
216 if (!nb_doms)
217 return;
218 set_i = isl_set_from_cloog_domain(doms[0]);
219 ctx = isl_set_get_ctx(set_i);
220 for (i = 0; i < nb_doms; i++) {
221 set_i = isl_set_from_cloog_domain(doms[i]);
222 assert(isl_set_n_basic_set(set_i) == 1);
225 follows = isl_alloc_array(ctx, unsigned char *, nb_doms);
226 assert(follows);
227 for (i = 0; i < nb_doms; ++i) {
228 follows[i] = isl_alloc_array(ctx, unsigned char, nb_doms);
229 assert(follows[i]);
230 for (j = 0; j < nb_doms; ++j)
231 follows[i][j] = 0;
234 for (i = 1; i < nb_doms; ++i) {
235 for (j = 0; j < i; ++j) {
236 if (follows[i][j] || follows[j][i])
237 continue;
238 set_i = isl_set_from_cloog_domain(doms[i]);
239 set_j = isl_set_from_cloog_domain(doms[j]);
240 bset_i = isl_set_copy_basic_set(set_i);
241 bset_j = isl_set_copy_basic_set(set_j);
242 cmp = isl_basic_set_compare_at(bset_i, bset_j, level-1);
243 isl_basic_set_free(bset_i);
244 isl_basic_set_free(bset_j);
245 if (!cmp)
246 continue;
247 if (cmp > 0) {
248 follows[i][j] = 1;
249 for (k = 0; k < i; ++k)
250 follows[i][k] |= follows[j][k];
251 } else {
252 follows[j][i] = 1;
253 for (k = 0; k < i; ++k)
254 follows[k][i] |= follows[k][j];
259 for (i = 0, j = 0; i < nb_doms; j = (j + 1) % nb_doms) {
260 for (k = 0; k < nb_doms; ++k)
261 if (follows[j][k])
262 break;
263 if (k < nb_doms)
264 continue;
265 for (k = 0; k < nb_doms; ++k)
266 follows[k][j] = 0;
267 follows[j][j] = 1;
268 permut[i] = 1 + j;
269 ++i;
272 for (i = 0; i < nb_doms; ++i)
273 free(follows[i]);
274 free(follows);
279 * Check whether there is or may be any value of dom1 at the given level
280 * that is greater than or equal to a value of dom2 at the same level.
282 * Return
283 * 1 is there is or may be a greater-than pair.
284 * 0 if there is no greater-than pair, but there may be an equal-to pair
285 * -1 if there is definitely no such pair
287 int cloog_domain_follows(CloogDomain *dom1, CloogDomain *dom2, unsigned level)
289 isl_set *set1 = isl_set_from_cloog_domain(dom1);
290 isl_set *set2 = isl_set_from_cloog_domain(dom2);
291 int follows;
293 follows = isl_set_follows_at(set1, set2, level - 1);
294 assert(follows >= -1);
296 return follows;
301 * cloog_domain_empty function:
302 * Returns an empty domain of the same dimensions as template.
304 CloogDomain *cloog_domain_empty(CloogDomain *template)
306 isl_set *set = isl_set_from_cloog_domain(template);
307 return cloog_domain_from_isl_set(isl_set_empty_like(set));
312 * Return 1 if the specified dimension has both an upper and a lower bound.
314 int cloog_domain_is_bounded(CloogDomain *dom, unsigned level)
316 isl_set *set = isl_set_from_cloog_domain(dom);
317 return isl_set_dim_is_bounded(set, isl_dim_set, level - 1);
321 /******************************************************************************
322 * Structure display function *
323 ******************************************************************************/
327 * cloog_domain_print_structure :
328 * this function is a more human-friendly way to display the CloogDomain data
329 * structure, it only shows the constraint system and includes an indentation
330 * level (level) in order to work with others print_structure functions.
332 void cloog_domain_print_structure(FILE *file, CloogDomain *domain, int level,
333 const char *name)
335 int i ;
336 isl_set *set = isl_set_from_cloog_domain(domain);
338 /* Go to the right level. */
339 for (i = 0; i < level; i++)
340 fprintf(file, "|\t");
342 if (!set) {
343 fprintf(file, "+-- Null CloogDomain\n");
344 return;
346 fprintf(file, "+-- %s\n", name);
347 for (i = 0; i < level+1; ++i)
348 fprintf(file, "|\t");
350 isl_set_print(set, file, 0, ISL_FORMAT_ISL);
352 fprintf(file, "\n");
356 /******************************************************************************
357 * Memory deallocation function *
358 ******************************************************************************/
361 void cloog_domain_list_free(CloogDomainList *list)
363 CloogDomainList *next;
365 for ( ; list; list = next) {
366 next = list->next;
367 cloog_domain_free(list->domain);
368 free(list);
374 * cloog_scattering_list_free function:
375 * This function frees the allocated memory for a CloogScatteringList structure.
377 void cloog_scattering_list_free(CloogScatteringList *list)
379 while (list != NULL) {
380 CloogScatteringList *temp = list->next;
381 isl_map *map = isl_map_from_cloog_scattering(list->scatt);
382 isl_map_free(map);
383 free(list);
384 list = temp;
389 /******************************************************************************
390 * Reading function *
391 ******************************************************************************/
395 * cloog_domain_read_context function:
396 * Read parameter domain.
398 CloogDomain *cloog_domain_read_context(CloogState *state, FILE *input)
400 struct isl_ctx *ctx = state->backend->ctx;
401 isl_set *set;
403 set = isl_set_read_from_file(ctx, input, 0);
404 set = isl_set_move_dims(set, isl_dim_param, 0,
405 isl_dim_set, 0, isl_set_dim(set, isl_dim_set));
407 return cloog_domain_from_isl_set(set);
412 * cloog_domain_from_context
413 * Reinterpret context by turning parameters into variables.
415 CloogDomain *cloog_domain_from_context(CloogDomain *context)
417 isl_set *set = isl_set_from_cloog_domain(context);
419 set = isl_set_move_dims(set, isl_dim_set, 0,
420 isl_dim_param, 0, isl_set_dim(set, isl_dim_param));
422 return cloog_domain_from_isl_set(set);
427 * cloog_domain_union_read function:
428 * This function reads a union of polyhedra into a file (input) and
429 * returns a pointer to a CloogDomain containing the read information.
431 CloogDomain *cloog_domain_union_read(CloogState *state,
432 FILE *input, int nb_parameters)
434 struct isl_ctx *ctx = state->backend->ctx;
435 struct isl_set *set;
437 set = isl_set_read_from_file(ctx, input, nb_parameters);
438 return cloog_domain_from_isl_set(set);
443 * cloog_domain_read_scattering function:
444 * This function reads in a scattering function from the file input.
446 * We try to read the scattering relation as a map, but if it is
447 * specified in the original PolyLib format, then isl_map_read_from_file
448 * will treat the input as a set return a map with zero input dimensions.
449 * In this case, we need to decompose the set into a map from
450 * scattering dimensions to domain dimensions and then invert the
451 * resulting map.
453 CloogScattering *cloog_domain_read_scattering(CloogDomain *domain, FILE *input)
455 isl_set *set = isl_set_from_cloog_domain(domain);
456 isl_ctx *ctx = isl_set_get_ctx(set);
457 struct isl_map *scat;
458 unsigned nparam;
459 unsigned dim;
460 unsigned n_scat;
462 dim = isl_set_dim(set, isl_dim_set);
463 nparam = isl_set_dim(set, isl_dim_param);
464 scat = isl_map_read_from_file(ctx, input, nparam);
465 if (isl_map_dim(scat, isl_dim_in) != dim) {
466 n_scat = isl_map_dim(scat, isl_dim_out) - dim;
467 scat = isl_map_move_dims(scat, isl_dim_in, 0,
468 isl_dim_out, n_scat, dim);
470 return cloog_scattering_from_isl_map(scat);
473 /******************************************************************************
474 * CloogMatrix Reading function *
475 ******************************************************************************/
478 * isl_constraint_read_from_matrix:
479 * Convert a single line of a matrix to a isl_constraint.
480 * Returns a pointer to the constraint if successful; NULL otherwise.
482 static struct isl_constraint *isl_constraint_read_from_matrix(
483 struct isl_dim *dim, cloog_int_t *row)
485 struct isl_constraint *constraint;
486 int j;
487 int nvariables = isl_dim_size(dim, isl_dim_set);
488 int nparam = isl_dim_size(dim, isl_dim_param);
490 if (cloog_int_is_zero(row[0]))
491 constraint = isl_equality_alloc(dim);
492 else
493 constraint = isl_inequality_alloc(dim);
495 for (j = 0; j < nvariables; ++j)
496 isl_constraint_set_coefficient(constraint, isl_dim_out, j,
497 row[1 + j]);
499 for (j = 0; j < nparam; ++j)
500 isl_constraint_set_coefficient(constraint, isl_dim_param, j,
501 row[1 + nvariables + j]);
503 isl_constraint_set_constant(constraint, row[1 + nvariables + nparam]);
505 return constraint;
509 * isl_basic_set_read_from_matrix:
510 * Convert matrix to basic_set. The matrix contains nparam parameter columns.
511 * Returns a pointer to the basic_set if successful; NULL otherwise.
513 static struct isl_basic_set *isl_basic_set_read_from_matrix(struct isl_ctx *ctx,
514 CloogMatrix* matrix, int nparam)
516 struct isl_dim *dim;
517 struct isl_basic_set *bset;
518 int i;
519 unsigned nrows, ncolumns;
521 nrows = matrix->NbRows;
522 ncolumns = matrix->NbColumns;
523 int nvariables = ncolumns - 2 - nparam;
525 dim = isl_dim_set_alloc(ctx, nparam, nvariables);
527 bset = isl_basic_set_universe(isl_dim_copy(dim));
529 for (i = 0; i < nrows; ++i) {
530 cloog_int_t *row = matrix->p[i];
531 struct isl_constraint *constraint =
532 isl_constraint_read_from_matrix(isl_dim_copy(dim), row);
533 bset = isl_basic_set_add_constraint(bset, constraint);
536 isl_dim_free(dim);
538 return bset;
542 * cloog_domain_from_cloog_matrix:
543 * Create a CloogDomain containing the constraints described in matrix.
544 * nparam is the number of parameters contained in the domain.
545 * Returns a pointer to the CloogDomain if successful; NULL otherwise.
547 CloogDomain *cloog_domain_from_cloog_matrix(CloogState *state,
548 CloogMatrix *matrix, int nparam)
550 struct isl_ctx *ctx = state->backend->ctx;
551 struct isl_basic_set *bset;
553 bset = isl_basic_set_read_from_matrix(ctx, matrix, nparam);
555 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
559 * cloog_scattering_from_cloog_matrix:
560 * Create a CloogScattering containing the constraints described in matrix.
561 * nparam is the number of parameters contained in the domain.
562 * Returns a pointer to the CloogScattering if successful; NULL otherwise.
564 CloogScattering *cloog_scattering_from_cloog_matrix(CloogState *state,
565 CloogMatrix *matrix, int nb_scat, int nb_par)
567 struct isl_ctx *ctx = state->backend->ctx;
568 struct isl_basic_set *bset;
569 struct isl_basic_map *scat;
570 struct isl_dim *dims;
571 unsigned dim;
573 bset = isl_basic_set_read_from_matrix(ctx, matrix, nb_par);
574 dim = isl_basic_set_n_dim(bset) - nb_scat;
575 dims = isl_dim_alloc(ctx, nb_par, nb_scat, dim);
577 scat = isl_basic_map_from_basic_set(bset, dims);
578 scat = isl_basic_map_reverse(scat);
579 return cloog_scattering_from_isl_map(isl_map_from_basic_map(scat));
583 /******************************************************************************
584 * Processing functions *
585 ******************************************************************************/
590 * cloog_domain_isempty function:
592 int cloog_domain_isempty(CloogDomain *domain)
594 isl_set *set = isl_set_from_cloog_domain(domain);
595 return isl_set_is_empty(set);
600 * cloog_domain_universe function:
601 * This function returns the complete dim-dimensional space.
603 CloogDomain *cloog_domain_universe(CloogState *state, unsigned dim)
605 struct isl_dim *dims;
606 struct isl_basic_set *bset;
608 dims = isl_dim_set_alloc(state->backend->ctx, 0, dim);
609 bset = isl_basic_set_universe(dims);
610 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
615 * cloog_domain_project function:
616 * This function returns the projection of
617 * (domain) on the (level) first dimensions (i.e. outer loops).
619 CloogDomain *cloog_domain_project(CloogDomain *domain, int level)
621 isl_set *set = isl_set_from_cloog_domain(domain);
622 set = isl_set_remove_dims(isl_set_copy(set), isl_dim_set,
623 level, isl_set_n_dim(set) - level);
624 set = isl_set_compute_divs(set);
625 if (level > 0)
626 set = isl_set_remove_divs_involving_dims(set,
627 isl_dim_set, level - 1, 1);
628 return cloog_domain_from_isl_set(set);
633 * cloog_domain_extend function:
634 * This function returns the (domain) given as input with (dim)
635 * dimensions and (nb_par) parameters.
636 * This function does not free (domain), and returns a new CloogDomain.
638 CloogDomain *cloog_domain_extend(CloogDomain *domain, int dim)
640 isl_set *set = isl_set_from_cloog_domain(domain);
641 int n = isl_set_dim(set, isl_dim_set);
642 set = isl_set_add_dims(isl_set_copy(set), isl_dim_set, dim - n);
643 return cloog_domain_from_isl_set(set);
648 * cloog_domain_never_integral function:
649 * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0.
650 * There is no need to check for such constraints explicitly for the isl
651 * backend.
653 int cloog_domain_never_integral(CloogDomain * domain)
655 isl_set *set = isl_set_from_cloog_domain(domain);
656 return isl_set_is_empty(set);
661 * Check whether the loop at "level" is executed at most once.
662 * We construct a map that maps all remaining variables to this iterator
663 * and check whether this map is single valued.
665 * Alternatively, we could have mapped the domain through a mapping
666 * [p] -> { [..., i] -> [..., i'] : i' > i }
667 * and then taken the intersection of the original domain and the transformed
668 * domain. If this intersection is empty, then the corresponding
669 * loop is executed at most once.
671 int cloog_domain_is_otl(CloogDomain *domain, int level)
673 int otl;
674 isl_set *set = isl_set_from_cloog_domain(domain);
675 isl_map *map;
677 map = isl_map_from_domain(isl_set_copy(set));
678 map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_in, level - 1, 1);
679 otl = isl_map_is_single_valued(map);
680 isl_map_free(map);
682 return otl;
687 * cloog_domain_stride function:
688 * This function finds the stride imposed to unknown with the column number
689 * 'strided_level' in order to be integral. For instance, if we have a
690 * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral
691 * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to
692 * the unknown i. The function returns the imposed stride in a parameter field.
693 * - domain is the set of constraint we have to consider,
694 * - strided_level is the column number of the unknown for which a stride have
695 * to be found,
696 * - looking_level is the column number of the unknown that impose a stride to
697 * the first unknown.
698 * - stride is the stride that is returned back as a function parameter.
699 * - offset is the value of the constant c if the condition is of the shape
700 * (i + c)%s = 0, s being the stride.
702 void cloog_domain_stride(CloogDomain *domain, int strided_level,
703 cloog_int_t *stride, cloog_int_t *offset)
705 isl_set *set = isl_set_from_cloog_domain(domain);
706 isl_set_dim_residue_class(set, strided_level - 1, stride, offset);
707 if (!isl_int_is_zero(*offset))
708 isl_int_sub(*offset, *stride, *offset);
709 return;
713 struct cloog_can_stride {
714 int level;
715 int can_stride;
718 static int constraint_can_stride(__isl_take isl_constraint *c, void *user)
720 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
721 int i;
722 isl_int v;
723 unsigned n_div;
725 if (isl_constraint_is_equality(c)) {
726 isl_constraint_free(c);
727 return 0;
730 isl_int_init(v);
731 isl_constraint_get_coefficient(c, isl_dim_set, ccs->level - 1, &v);
732 if (isl_int_is_pos(v)) {
733 n_div = isl_constraint_dim(c, isl_dim_div);
734 for (i = 0; i < n_div; ++i) {
735 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
736 if (!isl_int_is_zero(v))
737 break;
739 if (i < n_div)
740 ccs->can_stride = 0;
742 isl_int_clear(v);
743 isl_constraint_free(c);
745 return 0;
748 static int basic_set_can_stride(__isl_take isl_basic_set *bset, void *user)
750 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
751 int r;
753 r = isl_basic_set_foreach_constraint(bset, constraint_can_stride, ccs);
754 isl_basic_set_free(bset);
755 return r;
760 * Return 1 if CLooG is allowed to perform stride detection on level "level"
761 * and 0 otherwise.
762 * Currently, stride detection is only allowed when none of the lower
763 * bound constraints involve any existentially quantified variables.
764 * The reason is that the current isl interface does not make it
765 * easy to construct an integer division that depends on other integer
766 * divisions.
767 * By not allowing existentially quantified variables in the constraints,
768 * we can ignore them in cloog_domain_stride_lower_bound.
770 int cloog_domain_can_stride(CloogDomain *domain, int level)
772 struct cloog_can_stride ccs = { level, 1 };
773 isl_set *set = isl_set_from_cloog_domain(domain);
774 int r;
775 r = isl_set_foreach_basic_set(set, basic_set_can_stride, &ccs);
776 assert(r == 0);
777 return ccs.can_stride;
781 struct cloog_stride_lower {
782 int level;
783 CloogStride *stride;
784 isl_set *set;
785 isl_basic_set *bounds;
788 /* If the given constraint is a lower bound on csl->level, then add
789 * a lower bound to csl->bounds that makes sure that the remainder
790 * of the smallest value on division by csl->stride is equal to csl->offset.
792 * In particular, the given lower bound is of the form
794 * a i + f >= 0
796 * where f may depend on the parameters and other iterators.
797 * The stride is s and the offset is d.
798 * The lower bound -f/a may not satisfy the above condition. In fact,
799 * it may not even be integral. We want to round this value of i up
800 * to the nearest value that satisfies the condition and add the corresponding
801 * lower bound constraint. This nearest value is obtained by rounding
802 * i - d up to the nearest multiple of s.
803 * That is, we first subtract d
805 * i' = -f/a - d
807 * then we round up to the nearest multiple of s
809 * i'' = s * ceil(i'/s)
811 * and finally, we add d again
813 * i''' = i'' + d
815 * and impose the constraint i >= i'''.
817 * We find
819 * i'' = s * ceil((-f - a * d)/(a * s)) = - s * floor((f + a * d)/(a * s))
821 * i >= - s * floor((f + a * d)/(a * s)) + d
823 * or
824 * i + s * floor((f + a * d)/(a * s)) - d >= 0
826 static int constraint_stride_lower(__isl_take isl_constraint *c, void *user)
828 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
829 isl_int v;
830 isl_constraint *bound;
831 isl_aff *b;
833 if (isl_constraint_is_equality(c)) {
834 isl_constraint_free(c);
835 return 0;
838 isl_int_init(v);
839 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
840 if (!isl_int_is_pos(v)) {
841 isl_int_clear(v);
842 isl_constraint_free(c);
844 return 0;
847 b = isl_constraint_get_bound(c, isl_dim_set, csl->level - 1);
849 b = isl_aff_neg(b);
850 b = isl_aff_add_constant(b, csl->stride->offset);
851 b = isl_aff_scale_down(b, csl->stride->stride);
852 b = isl_aff_floor(b);
853 b = isl_aff_scale(b, csl->stride->stride);
854 isl_int_neg(v, csl->stride->offset);
855 b = isl_aff_add_constant(b, v);
856 b = isl_aff_add_coefficient_si(b, isl_dim_set, csl->level - 1, 1);
858 bound = isl_inequality_from_aff(b);
860 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
862 isl_int_clear(v);
863 isl_constraint_free(c);
865 return 0;
868 /* This functions performs essentially the same operation as
869 * constraint_stride_lower, the only difference being that the offset d
870 * is not a constant, but an affine expression in terms of the parameters
871 * and earlier variables. In particular the affine expression is equal
872 * to the coefficients of stride->constraint multiplied by stride->factor.
873 * As in constraint_stride_lower, we add an extra bound
875 * i + s * floor((f + a * d)/(a * s)) - d >= 0
877 * for each lower bound
879 * a i + f >= 0
881 * where d is not the aforementioned affine expression.
883 static int constraint_stride_lower_c(__isl_take isl_constraint *c, void *user)
885 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
886 isl_int v;
887 isl_constraint *bound;
888 isl_constraint *csl_c;
889 isl_aff *d, *b;
891 if (isl_constraint_is_equality(c)) {
892 isl_constraint_free(c);
893 return 0;
896 isl_int_init(v);
897 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
898 if (!isl_int_is_pos(v)) {
899 isl_int_clear(v);
900 isl_constraint_free(c);
902 return 0;
905 csl_c = cloog_constraint_to_isl(csl->stride->constraint);
907 d = isl_constraint_get_aff(csl_c);
908 d = isl_aff_drop_dims(d, isl_dim_div, 0, isl_aff_dim(d, isl_dim_div));
909 d = isl_aff_set_coefficient_si(d, isl_dim_set, csl->level - 1, 0);
910 d = isl_aff_scale(d, csl->stride->factor);
912 b = isl_constraint_get_bound(c, isl_dim_set, csl->level - 1);
914 b = isl_aff_neg(b);
915 b = isl_aff_add(b, isl_aff_copy(d));
916 b = isl_aff_scale_down(b, csl->stride->stride);
917 b = isl_aff_floor(b);
918 b = isl_aff_scale(b, csl->stride->stride);
919 b = isl_aff_sub(b, d);
920 b = isl_aff_add_coefficient_si(b, isl_dim_set, csl->level - 1, 1);
922 bound = isl_inequality_from_aff(b);
924 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
926 isl_int_clear(v);
927 isl_constraint_free(c);
929 return 0;
932 static int basic_set_stride_lower(__isl_take isl_basic_set *bset, void *user)
934 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
935 int r;
937 csl->bounds = isl_basic_set_universe_like(bset);
938 if (csl->stride->constraint)
939 r = isl_basic_set_foreach_constraint(bset,
940 &constraint_stride_lower_c, csl);
941 else
942 r = isl_basic_set_foreach_constraint(bset,
943 &constraint_stride_lower, csl);
944 bset = isl_basic_set_intersect(bset, csl->bounds);
945 csl->set = isl_set_union(csl->set, isl_set_from_basic_set(bset));
947 return r;
951 * Update the lower bounds at level "level" to the given stride information.
952 * That is, make sure that the remainder on division by "stride"
953 * is equal to "offset".
955 CloogDomain *cloog_domain_stride_lower_bound(CloogDomain *domain, int level,
956 CloogStride *stride)
958 struct cloog_stride_lower csl;
959 isl_set *set = isl_set_from_cloog_domain(domain);
960 int r;
962 csl.stride = stride;
963 csl.level = level;
964 csl.set = isl_set_empty_like(set);
966 r = isl_set_foreach_basic_set(set, basic_set_stride_lower, &csl);
967 assert(r == 0);
969 cloog_domain_free(domain);
970 return cloog_domain_from_isl_set(csl.set);
974 /* Add stride constraint, if any, to domain.
976 CloogDomain *cloog_domain_add_stride_constraint(CloogDomain *domain,
977 CloogStride *stride)
979 isl_constraint *c;
980 isl_set *set;
982 if (!stride || !stride->constraint)
983 return domain;
985 set = isl_set_from_cloog_domain(domain);
986 c = isl_constraint_copy(cloog_constraint_to_isl(stride->constraint));
988 set = isl_set_add_constraint(set, c);
990 return cloog_domain_from_isl_set(set);
995 * cloog_domain_lazy_equal function:
996 * This function returns 1 if the domains given as input are the same, 0 if it
997 * is unable to decide.
999 int cloog_domain_lazy_equal(CloogDomain *d1, CloogDomain *d2)
1001 isl_set *set1 = isl_set_from_cloog_domain(d1);
1002 isl_set *set2 = isl_set_from_cloog_domain(d2);
1003 return isl_set_fast_is_equal(set1, set2);
1006 struct cloog_bound_split {
1007 isl_set *set;
1008 int level;
1009 int lower;
1010 int upper;
1013 static int constraint_bound_split(__isl_take isl_constraint *c, void *user)
1015 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1016 isl_int v;
1017 int i;
1018 int handle = 0;
1020 isl_int_init(v);
1021 isl_constraint_get_coefficient(c, isl_dim_set, cbs->level - 1, &v);
1022 if (!cbs->lower && isl_int_is_pos(v))
1023 cbs->lower = handle = 1;
1024 else if (!cbs->upper && isl_int_is_neg(v))
1025 cbs->upper = handle = 1;
1026 if (handle) {
1027 for (i = 0; i < isl_set_dim(cbs->set, isl_dim_param); ++i) {
1028 isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
1029 if (isl_int_is_zero(v))
1030 continue;
1031 cbs->set = isl_set_split_dims(cbs->set,
1032 isl_dim_param, i, 1);
1035 isl_int_clear(v);
1036 isl_constraint_free(c);
1038 return (cbs->lower && cbs->upper) ? -1 : 0;
1041 static int basic_set_bound_split(__isl_take isl_basic_set *bset, void *user)
1043 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1044 int r;
1046 cbs->lower = 0;
1047 cbs->upper = 0;
1048 r = isl_basic_set_foreach_constraint(bset, constraint_bound_split, cbs);
1049 isl_basic_set_free(bset);
1050 return ((!cbs->lower || !cbs->upper) && r < 0) ? -1 : 0;
1054 * Return a union of sets S_i such that the convex hull of "dom",
1055 * when intersected with one the sets S_i, will have an upper and
1056 * lower bound for the dimension at "level" (provided "dom" itself
1057 * has such bounds for the dimensions).
1059 * We currently take a very simple approach. For each of the basic
1060 * sets in "dom" we pick a lower and an upper bound and split the
1061 * range of any parameter involved in these two bounds in a
1062 * nonnegative and a negative part. This ensures that the symbolic
1063 * constant in these two constraints are themselves bounded and
1064 * so there will be at least one upper and one lower bound
1065 * in the convex hull.
1067 CloogDomain *cloog_domain_bound_splitter(CloogDomain *dom, int level)
1069 struct cloog_bound_split cbs;
1070 isl_set *set = isl_set_from_cloog_domain(dom);
1071 int r;
1072 cbs.level = level;
1073 cbs.set = isl_set_universe_like(set);
1074 r = isl_set_foreach_basic_set(set, basic_set_bound_split, &cbs);
1075 assert(r == 0);
1076 return cloog_domain_from_isl_set(cbs.set);
1080 /* Check whether the union of scattering functions over all domains
1081 * is obviously injective.
1083 static int injective_scattering(CloogScatteringList *list)
1085 isl_map *map;
1086 isl_union_map *umap;
1087 int injective;
1088 int i = 0;
1089 char name[30];
1091 if (!list)
1092 return 1;
1094 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1095 snprintf(name, sizeof(name), "S%d", i);
1096 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1097 umap = isl_union_map_from_map(map);
1099 for (list = list->next, ++i; list; list = list->next, ++i) {
1100 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1101 snprintf(name, sizeof(name), "S%d", i);
1102 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1103 umap = isl_union_map_add_map(umap, map);
1106 injective = isl_union_map_plain_is_injective(umap);
1108 isl_union_map_free(umap);
1110 return injective;
1115 * cloog_scattering_lazy_block function:
1116 * This function returns 1 if the two scattering functions s1 and s2 given
1117 * as input are the same (except possibly for the final dimension, where we
1118 * allow a difference of 1), assuming that the domains on which this
1119 * scatterings are applied are the same.
1120 * In fact this function answers the question "can I
1121 * safely consider the two domains as only one with two statements (a block) ?".
1122 * A difference of 1 in the final dimension is only allowed if the
1123 * entire scattering function is injective.
1124 * - s1 and s2 are the two domains to check for blocking,
1125 * - scattering is the linked list of all domains,
1126 * - scattdims is the total number of scattering dimentions.
1128 int cloog_scattering_lazy_block(CloogScattering *s1, CloogScattering *s2,
1129 CloogScatteringList *scattering, int scattdims)
1131 int i;
1132 struct isl_dim *dim;
1133 struct isl_map *rel;
1134 struct isl_set *delta;
1135 isl_map *map1 = isl_map_from_cloog_scattering(s1);
1136 isl_map *map2 = isl_map_from_cloog_scattering(s2);
1137 int fixed, block;
1138 isl_int cst;
1139 unsigned n_scat;
1141 n_scat = isl_map_dim(map1, isl_dim_out);
1142 if (n_scat != isl_map_dim(map2, isl_dim_out))
1143 return 0;
1145 dim = isl_map_get_dim(map1);
1146 dim = isl_dim_map_from_set(isl_dim_domain(dim));
1147 rel = isl_map_identity(dim);
1148 rel = isl_map_apply_domain(rel, isl_map_copy(map1));
1149 rel = isl_map_apply_range(rel, isl_map_copy(map2));
1150 delta = isl_map_deltas(rel);
1151 isl_int_init(cst);
1152 for (i = 0; i < n_scat; ++i) {
1153 fixed = isl_set_fast_dim_is_fixed(delta, i, &cst);
1154 if (fixed != 1)
1155 break;
1156 if (isl_int_is_zero(cst))
1157 continue;
1158 if (i + 1 < n_scat)
1159 break;
1160 if (!isl_int_is_one(cst))
1161 break;
1162 if (!injective_scattering(scattering))
1163 break;
1165 block = i >= n_scat;
1166 isl_int_clear(cst);
1167 isl_set_free(delta);
1168 return block;
1173 * cloog_domain_lazy_disjoint function:
1174 * This function returns 1 if the domains given as input are disjoint, 0 if it
1175 * is unable to decide.
1177 int cloog_domain_lazy_disjoint(CloogDomain *d1, CloogDomain *d2)
1179 isl_set *set1 = isl_set_from_cloog_domain(d1);
1180 isl_set *set2 = isl_set_from_cloog_domain(d2);
1181 return isl_set_fast_is_disjoint(set1, set2);
1186 * cloog_scattering_list_lazy_same function:
1187 * This function returns 1 if two domains in the list are the same, 0 if it
1188 * is unable to decide.
1190 int cloog_scattering_list_lazy_same(CloogScatteringList *list)
1192 CloogScatteringList *one, *other;
1193 isl_map *one_map, *other_map;
1195 for (one = list; one; one = one->next) {
1196 one_map = isl_map_from_cloog_scattering(one->scatt);
1197 for (other = one->next; other; other = other->next) {
1198 other_map = isl_map_from_cloog_scattering(other->scatt);
1199 if (isl_map_fast_is_equal(one_map, other_map))
1200 return 1;
1203 return 0;
1206 int cloog_domain_dimension(CloogDomain * domain)
1208 isl_set *set = isl_set_from_cloog_domain(domain);
1209 return isl_set_dim(set, isl_dim_set);
1212 int cloog_domain_parameter_dimension(CloogDomain *domain)
1214 isl_set *set = isl_set_from_cloog_domain(domain);
1215 return isl_set_dim(set, isl_dim_param);
1218 int cloog_scattering_dimension(CloogScattering *scatt, CloogDomain *domain)
1220 isl_map *map = isl_map_from_cloog_scattering(scatt);
1221 return isl_map_dim(map, isl_dim_out);
1224 int cloog_domain_isconvex(CloogDomain * domain)
1226 isl_set *set = isl_set_from_cloog_domain(domain);
1227 return isl_set_n_basic_set(set) <= 1;
1232 * cloog_domain_cut_first function:
1233 * This function splits off and returns the first convex set in the
1234 * union "domain". The remainder of the union is returned in rest.
1235 * The original "domain" itself is destroyed and may not be used
1236 * after a call to this function.
1238 CloogDomain *cloog_domain_cut_first(CloogDomain *domain, CloogDomain **rest)
1240 isl_set *set = isl_set_from_cloog_domain(domain);
1241 struct isl_basic_set *first;
1243 first = isl_set_copy_basic_set(set);
1244 set = isl_set_drop_basic_set(set, first);
1245 *rest = cloog_domain_from_isl_set(set);
1247 return cloog_domain_from_isl_set(isl_set_from_basic_set(first));
1252 * Given a union domain, try to find a simpler representation
1253 * using fewer sets in the union.
1254 * The original "domain" itself is destroyed and may not be used
1255 * after a call to this function.
1257 CloogDomain *cloog_domain_simplify_union(CloogDomain *domain)
1259 isl_set *set = isl_set_from_cloog_domain(domain);
1260 return cloog_domain_from_isl_set(isl_set_coalesce(set));
1265 * cloog_scattering_lazy_isscalar function:
1266 * this function returns 1 if the scattering dimension 'dimension' in the
1267 * scattering 'scatt' is constant.
1268 * If value is not NULL, then it is set to the constant value of dimension.
1270 int cloog_scattering_lazy_isscalar(CloogScattering *scatt, int dimension,
1271 cloog_int_t *value)
1273 isl_map *map = isl_map_from_cloog_scattering(scatt);
1274 return isl_map_fast_is_fixed(map, isl_dim_out, dimension, value);
1279 * cloog_domain_lazy_isconstant function:
1280 * this function returns 1 if the dimension 'dimension' in the
1281 * domain 'domain' is constant.
1282 * If value is not NULL, then it is set to the constant value of dimension.
1284 int cloog_domain_lazy_isconstant(CloogDomain *domain, int dimension,
1285 cloog_int_t *value)
1287 isl_set *set = isl_set_from_cloog_domain(domain);
1288 return isl_set_fast_dim_is_fixed(set, dimension, value);
1293 * cloog_scattering_erase_dimension function:
1294 * this function returns a CloogDomain structure builds from 'domain' where
1295 * we removed the dimension 'dimension' and every constraint involving this
1296 * dimension.
1298 CloogScattering *cloog_scattering_erase_dimension(CloogScattering *scattering,
1299 int dimension)
1301 isl_map *map = isl_map_from_cloog_scattering(scattering);
1302 map = isl_map_remove_dims(isl_map_copy(map), isl_dim_out, dimension, 1);
1303 return cloog_scattering_from_isl_map(map);
1307 * cloog_domain_cube:
1308 * Construct and return a dim-dimensional cube, with values ranging
1309 * between min and max in each dimension.
1311 CloogDomain *cloog_domain_cube(CloogState *state,
1312 int dim, cloog_int_t min, cloog_int_t max)
1314 int i;
1315 struct isl_basic_set *cube;
1316 struct isl_basic_set *interval;
1317 struct isl_basic_set_list *list;
1319 if (dim == 0)
1320 return cloog_domain_universe(state, dim);
1322 interval = isl_basic_set_interval(state->backend->ctx, min, max);
1323 list = isl_basic_set_list_alloc(state->backend->ctx, dim);
1324 for (i = 0; i < dim; ++i)
1325 list = isl_basic_set_list_add(list, isl_basic_set_copy(interval));
1326 isl_basic_set_free(interval);
1327 cube = isl_basic_set_list_product(list);
1328 return cloog_domain_from_isl_set(isl_set_from_basic_set(cube));
1333 * cloog_domain_scatter function:
1334 * This function add the scattering (scheduling) informations to a domain.
1336 CloogDomain *cloog_domain_scatter(CloogDomain *domain, CloogScattering *scatt)
1338 isl_set *set = isl_set_from_cloog_domain(domain);
1339 isl_map *map = isl_map_from_cloog_scattering(scatt);
1341 map = isl_map_reverse(isl_map_copy(map));
1342 map = isl_map_intersect_range(map, set);
1343 set = isl_set_flatten(isl_map_wrap(map));
1344 return cloog_domain_from_isl_set(set);
1347 static int add_domain_from_map(__isl_take isl_map *map, void *user)
1349 isl_dim *dim;
1350 const char *name;
1351 CloogDomain *domain;
1352 CloogScattering *scat;
1353 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1355 dim = isl_map_get_dim(map);
1356 name = isl_dim_get_tuple_name(dim, isl_dim_in);
1357 domain = cloog_domain_from_isl_set(isl_map_domain(isl_map_copy(map)));
1358 scat = cloog_scattering_from_isl_map(map);
1359 *ud = cloog_union_domain_add_domain(*ud, name, domain, scat, NULL);
1360 isl_dim_free(dim);
1362 return 0;
1366 * Construct a CloogUnionDomain from an isl_union_map representing
1367 * a global scattering function. The input is a mapping from different
1368 * spaces (different tuple names and possibly different dimensions)
1369 * to a common space. The iteration domains are set to the domains
1370 * in each space. The statement names are set to the names of the
1371 * spaces. The parameter names of the result are set to those of
1372 * the input, but the iterator and scattering dimension names are
1373 * left unspecified.
1375 CloogUnionDomain *cloog_union_domain_from_isl_union_map(
1376 __isl_take isl_union_map *umap)
1378 int i;
1379 int nparam;
1380 isl_dim *dim;
1381 CloogUnionDomain *ud;
1383 dim = isl_union_map_get_dim(umap);
1384 nparam = isl_dim_size(dim, isl_dim_param);
1386 ud = cloog_union_domain_alloc(nparam);
1388 for (i = 0; i < nparam; ++i) {
1389 const char *s = isl_dim_get_name(dim, isl_dim_param, i);
1390 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1392 isl_dim_free(dim);
1394 if (isl_union_map_foreach_map(umap, &add_domain_from_map, &ud) < 0) {
1395 isl_union_map_free(umap);
1396 cloog_union_domain_free(ud);
1397 assert(0);
1400 isl_union_map_free(umap);
1402 return ud;
1405 static int count_same_name(__isl_keep isl_dim *dim,
1406 enum isl_dim_type type, unsigned pos, const char *name)
1408 enum isl_dim_type t;
1409 unsigned p, s;
1410 int count = 0;
1411 int len = strlen(name);
1413 for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) {
1414 s = t == type ? pos : isl_dim_size(dim, t);
1415 for (p = 0; p < s; ++p) {
1416 const char *n = isl_dim_get_name(dim, t, p);
1417 if (n && !strncmp(n, name, len))
1418 count++;
1421 return count;
1424 static int add_domain(__isl_take isl_set *set, void *user)
1426 int i, nvar;
1427 isl_ctx *ctx;
1428 isl_dim *dim;
1429 char buffer[20];
1430 const char *name;
1431 CloogDomain *domain;
1432 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1434 ctx = isl_set_get_ctx(set);
1435 dim = isl_set_get_dim(set);
1436 name = isl_dim_get_tuple_name(dim, isl_dim_set);
1437 set = isl_set_flatten(set);
1438 set = isl_set_set_tuple_name(set, NULL);
1439 domain = cloog_domain_from_isl_set(set);
1440 *ud = cloog_union_domain_add_domain(*ud, name, domain, NULL, NULL);
1442 nvar = isl_dim_size(dim, isl_dim_set);
1443 for (i = 0; i < nvar; ++i) {
1444 char *long_name = NULL;
1445 int n;
1447 name = isl_dim_get_name(dim, isl_dim_set, i);
1448 if (!name) {
1449 snprintf(buffer, sizeof(buffer), "i%d", i);
1450 name = buffer;
1452 n = count_same_name(dim, isl_dim_set, i, name);
1453 if (n) {
1454 int size = strlen(name) + 10;
1455 long_name = isl_alloc_array(ctx, char, size);
1456 if (!long_name)
1457 cloog_die("memory overflow.\n");
1458 snprintf(long_name, size, "%s_%d", name, n);
1459 name = long_name;
1461 *ud = cloog_union_domain_set_name(*ud, CLOOG_ITER, i, name);
1462 free(long_name);
1464 isl_dim_free(dim);
1466 return 0;
1470 * Construct a CloogUnionDomain from an isl_union_set.
1471 * The statement names are set to the names of the
1472 * spaces. The parameter and iterator names of the result are set to those of
1473 * the input, but the scattering dimension names are left unspecified.
1475 CloogUnionDomain *cloog_union_domain_from_isl_union_set(
1476 __isl_take isl_union_set *uset)
1478 int i;
1479 int nparam;
1480 isl_dim *dim;
1481 CloogUnionDomain *ud;
1483 dim = isl_union_set_get_dim(uset);
1484 nparam = isl_dim_size(dim, isl_dim_param);
1486 ud = cloog_union_domain_alloc(nparam);
1488 for (i = 0; i < nparam; ++i) {
1489 const char *s = isl_dim_get_name(dim, isl_dim_param, i);
1490 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1492 isl_dim_free(dim);
1494 if (isl_union_set_foreach_set(uset, &add_domain, &ud) < 0) {
1495 isl_union_set_free(uset);
1496 cloog_union_domain_free(ud);
1497 assert(0);
1500 isl_union_set_free(uset);
1502 return ud;
1505 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
1506 static void Euclid(cloog_int_t a, cloog_int_t b,
1507 cloog_int_t *x, cloog_int_t *y, cloog_int_t *g)
1509 cloog_int_t c, d, e, f, tmp;
1511 cloog_int_init(c);
1512 cloog_int_init(d);
1513 cloog_int_init(e);
1514 cloog_int_init(f);
1515 cloog_int_init(tmp);
1516 cloog_int_abs(c, a);
1517 cloog_int_abs(d, b);
1518 cloog_int_set_si(e, 1);
1519 cloog_int_set_si(f, 0);
1520 while (cloog_int_is_pos(d)) {
1521 cloog_int_tdiv_q(tmp, c, d);
1522 cloog_int_mul(tmp, tmp, f);
1523 cloog_int_sub(e, e, tmp);
1524 cloog_int_tdiv_q(tmp, c, d);
1525 cloog_int_mul(tmp, tmp, d);
1526 cloog_int_sub(c, c, tmp);
1527 cloog_int_swap(c, d);
1528 cloog_int_swap(e, f);
1530 cloog_int_set(*g, c);
1531 if (cloog_int_is_zero(a))
1532 cloog_int_set_si(*x, 0);
1533 else if (cloog_int_is_pos(a))
1534 cloog_int_set(*x, e);
1535 else cloog_int_neg(*x, e);
1536 if (cloog_int_is_zero(b))
1537 cloog_int_set_si(*y, 0);
1538 else {
1539 cloog_int_mul(tmp, a, *x);
1540 cloog_int_sub(tmp, c, tmp);
1541 cloog_int_divexact(*y, tmp, b);
1543 cloog_int_clear(c);
1544 cloog_int_clear(d);
1545 cloog_int_clear(e);
1546 cloog_int_clear(f);
1547 cloog_int_clear(tmp);
1550 /* Construct a CloogStride from the given constraint for the given level,
1551 * if possible.
1552 * We first compute the gcd of the coefficients of the existentially
1553 * quantified variables and then remove any common factors it has
1554 * with the coefficient at the given level.
1555 * The result is the value of the stride and if it is not one,
1556 * then it is possible to construct a CloogStride.
1557 * The constraint leading to the stride is stored in the CloogStride
1558 * as well a value (factor) such that the product of this value
1559 * and the coefficient at the given level is equal to -1 modulo the stride.
1561 static CloogStride *construct_stride(isl_constraint *c, int level)
1563 int i, n, sign;
1564 isl_int v, m, gcd, stride, factor;
1565 CloogStride *s;
1567 if (!c)
1568 return NULL;
1570 isl_int_init(v);
1571 isl_int_init(m);
1572 isl_int_init(gcd);
1573 isl_int_init(factor);
1574 isl_int_init(stride);
1576 isl_constraint_get_coefficient(c, isl_dim_set, level - 1, &v);
1577 sign = isl_int_sgn(v);
1578 isl_int_abs(m, v);
1580 isl_int_set_si(gcd, 0);
1581 n = isl_constraint_dim(c, isl_dim_div);
1582 for (i = 0; i < n; ++i) {
1583 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
1584 isl_int_gcd(gcd, gcd, v);
1587 isl_int_gcd(v, m, gcd);
1588 isl_int_divexact(stride, gcd, v);
1590 if (isl_int_is_zero(stride) || isl_int_is_one(stride))
1591 s = NULL;
1592 else {
1593 Euclid(m, stride, &factor, &v, &gcd);
1594 if (sign > 0)
1595 isl_int_neg(factor, factor);
1597 c = isl_constraint_copy(c);
1598 s = cloog_stride_alloc_from_constraint(stride,
1599 cloog_constraint_from_isl_constraint(c), factor);
1602 isl_int_clear(stride);
1603 isl_int_clear(factor);
1604 isl_int_clear(gcd);
1605 isl_int_clear(m);
1606 isl_int_clear(v);
1608 return s;
1611 struct cloog_isl_find_stride_data {
1612 int level;
1613 CloogStride *stride;
1616 /* Check if the given constraint can be used to derive
1617 * a stride on the iterator identified by data->level.
1618 * We first check that there are some existentially quantified variables
1619 * and that the coefficient at data->level is non-zero.
1620 * Then we call construct_stride for further checks and the actual
1621 * construction of the CloogStride.
1623 static int find_stride(__isl_take isl_constraint *c, void *user)
1625 struct cloog_isl_find_stride_data *data;
1626 int n;
1627 isl_int v;
1629 data = (struct cloog_isl_find_stride_data *)user;
1631 if (data->stride) {
1632 isl_constraint_free(c);
1633 return 0;
1636 n = isl_constraint_dim(c, isl_dim_div);
1637 if (n == 0) {
1638 isl_constraint_free(c);
1639 return 0;
1642 isl_int_init(v);
1644 isl_constraint_get_coefficient(c, isl_dim_set, data->level - 1, &v);
1645 if (!isl_int_is_zero(v))
1646 data->stride = construct_stride(c, data->level);
1648 isl_int_clear(v);
1650 isl_constraint_free(c);
1652 return 0;
1655 /* Check if the given list of domains has a common stride on the given level.
1656 * If so, return a pointer to a CloogStride object. If not, return NULL.
1658 * We project out all later variables, take the union and compute
1659 * the affine hull of the union. Then we check the (equality)
1660 * constraints in this affine hull for imposing a stride.
1662 CloogStride *cloog_domain_list_stride(CloogDomainList *list, int level)
1664 struct cloog_isl_find_stride_data data = { level, NULL };
1665 isl_set *set;
1666 isl_basic_set *aff;
1667 int first = level;
1668 int n;
1669 int r;
1671 set = isl_set_from_cloog_domain(list->domain);
1672 n = isl_set_dim(set, isl_dim_set) - first;
1673 set = isl_set_project_out(isl_set_copy(set), isl_dim_set, first, n);
1675 for (list = list->next; list; list = list->next) {
1676 isl_set *set_i = isl_set_from_cloog_domain(list->domain);
1677 n = isl_set_dim(set_i, isl_dim_set) - first;
1678 set_i = isl_set_project_out(isl_set_copy(set_i),
1679 isl_dim_set, first, n);
1680 set = isl_set_union(set, set_i);
1682 aff = isl_set_affine_hull(set);
1684 r = isl_basic_set_foreach_constraint(aff, &find_stride, &data);
1685 assert(r == 0);
1687 isl_basic_set_free(aff);
1689 return data.stride;
1692 struct cloog_can_unroll {
1693 int can_unroll;
1694 int level;
1695 isl_constraint *c;
1696 isl_set *set;
1697 isl_int *n;
1702 * Check if the given lower bound can be used for unrolling.
1703 * If the lower bound involves any existentially quantified
1704 * variables, we currently punt.
1705 * Otherwise we compute the maximal value of (i - ceil(l) + 1),
1706 * with l the given lower bound and i the iterator identified by level.
1708 static int is_valid_unrolling_lower_bound(struct cloog_can_unroll *ccu,
1709 __isl_keep isl_constraint *c)
1711 unsigned n_div;
1712 isl_aff *aff;
1713 enum isl_lp_result res;
1715 n_div = isl_constraint_dim(c, isl_dim_div);
1716 if (isl_constraint_involves_dims(c, isl_dim_div, 0, n_div))
1717 return 0;
1719 aff = isl_constraint_get_bound(c, isl_dim_set, ccu->level - 1);
1720 aff = isl_aff_ceil(aff);
1721 aff = isl_aff_neg(aff);
1722 aff = isl_aff_add_coefficient_si(aff, isl_dim_set, ccu->level - 1, 1);
1723 res = isl_set_max(ccu->set, aff, ccu->n);
1724 isl_aff_free(aff);
1726 if (res == isl_lp_unbounded)
1727 return 0;
1729 assert(res == isl_lp_ok);
1731 cloog_int_add_ui(*ccu->n, *ccu->n, 1);
1733 return 1;
1737 /* Check if we can unroll based on the given constraint.
1738 * Only lower bounds can be used.
1739 * Record it if it turns out to be usable and if we haven't recorded
1740 * any other constraint already.
1742 static int constraint_can_unroll(__isl_take isl_constraint *c, void *user)
1744 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1745 isl_int v;
1747 isl_int_init(v);
1748 isl_constraint_get_coefficient(c, isl_dim_set, ccu->level - 1, &v);
1749 if (isl_int_is_pos(v)) {
1750 if (!ccu->c && is_valid_unrolling_lower_bound(ccu, c))
1751 ccu->c = isl_constraint_copy(c);
1753 isl_int_clear(v);
1754 isl_constraint_free(c);
1756 return 0;
1760 /* Check if we can unroll the domain at the current level.
1761 * If the domain is a union, we cannot. Otherwise, we check the
1762 * constraints.
1764 static int basic_set_can_unroll(__isl_take isl_basic_set *bset, void *user)
1766 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1767 int r = 0;
1769 if (ccu->c || !ccu->can_unroll)
1770 ccu->can_unroll = 0;
1771 else {
1772 bset = isl_basic_set_remove_redundancies(bset);
1773 r = isl_basic_set_foreach_constraint(bset,
1774 &constraint_can_unroll, ccu);
1776 isl_basic_set_free(bset);
1777 return r;
1781 /* Check if we can unroll the given domain at the given level, and
1782 * if so, return the single lower bound in *lb and an upper bound
1783 * on the number of iterations in *n.
1784 * If we cannot unroll, return 0 and set *lb to NULL.
1786 * We can unroll, if we can identify a lower bound on level
1787 * such that the number of iterations is bounded by a constant.
1789 int cloog_domain_can_unroll(CloogDomain *domain, int level, cloog_int_t *n,
1790 CloogConstraint **lb)
1792 isl_set *set = isl_set_from_cloog_domain(domain);
1793 struct cloog_can_unroll ccu = { 1, level, NULL, set, n };
1794 int r;
1796 *lb = NULL;
1797 r = isl_set_foreach_basic_set(set, &basic_set_can_unroll, &ccu);
1798 assert(r == 0);
1799 if (!ccu.c)
1800 ccu.can_unroll = 0;
1801 if (!ccu.can_unroll) {
1802 isl_constraint_free(ccu.c);
1803 return 0;
1806 *lb = cloog_constraint_from_isl_constraint(ccu.c);
1808 return ccu.can_unroll;
1812 /* Fix the iterator i at the given level to l + o,
1813 * where l is prescribed by the constraint lb and o is equal to offset.
1814 * In particular, if lb is the constraint
1816 * a i >= f(j)
1818 * then l = ceil(f(j)/a).
1820 CloogDomain *cloog_domain_fixed_offset(CloogDomain *domain,
1821 int level, CloogConstraint *lb, cloog_int_t offset)
1823 isl_aff *aff;
1824 isl_set *set = isl_set_from_cloog_domain(domain);
1825 isl_constraint *c;
1826 isl_constraint *eq;
1828 c = cloog_constraint_to_isl(lb);
1829 aff = isl_constraint_get_bound(c, isl_dim_set, level - 1);
1830 aff = isl_aff_ceil(aff);
1831 aff = isl_aff_add_coefficient_si(aff, isl_dim_set, level - 1, -1);
1832 aff = isl_aff_add_constant(aff, offset);
1833 eq = isl_equality_from_aff(aff);
1834 set = isl_set_add_constraint(set, eq);
1836 return cloog_domain_from_isl_set(set);