Add OpenScop support
[cloog.git] / source / isl / domain.c
blobd508bb2e72815336ffeb6e91737c100783040e1d
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/ilp.h>
10 #include <isl/aff.h>
12 #ifdef OSL_SUPPORT
13 #include <osl/relation.h>
14 #endif
16 CloogDomain *cloog_domain_from_isl_set(struct isl_set *set)
18 set = isl_set_detect_equalities(set);
19 set = isl_set_compute_divs(set);
20 return (CloogDomain *)set;
23 __isl_give isl_set *isl_set_from_cloog_domain(CloogDomain *domain)
25 return (isl_set *)domain;
28 CloogScattering *cloog_scattering_from_isl_map(struct isl_map *map)
30 return (CloogScattering *)map;
33 __isl_give isl_map *isl_map_from_cloog_scattering(CloogScattering *scattering)
35 return (isl_map *)scattering;
39 /**
40 * Returns true if each scattering dimension is defined in terms
41 * of the original iterators.
43 int cloog_scattering_fully_specified(CloogScattering *scattering,
44 CloogDomain *domain)
46 isl_map *map = isl_map_from_cloog_scattering(scattering);
47 return isl_map_is_single_valued(map);
51 CloogConstraintSet *cloog_domain_constraints(CloogDomain *domain)
53 isl_basic_set *bset;
54 isl_set *set = isl_set_from_cloog_domain(domain);
55 assert(isl_set_n_basic_set(set) == 1);
56 bset = isl_set_copy_basic_set(set);
57 return cloog_constraint_set_from_isl_basic_set(bset);
61 void cloog_domain_print_constraints(FILE *foo, CloogDomain *domain,
62 int print_number)
64 isl_basic_set *bset;
65 isl_set *set = isl_set_from_cloog_domain(domain);
67 if (print_number)
68 isl_set_print(set, foo, 0, ISL_FORMAT_EXT_POLYLIB);
69 else {
70 assert(isl_set_n_basic_set(set) == 1);
71 bset = isl_set_copy_basic_set(set);
72 isl_basic_set_print(bset, foo,
73 0, NULL, NULL, ISL_FORMAT_POLYLIB);
74 isl_basic_set_free(bset);
79 void cloog_scattering_print_constraints(FILE *foo, CloogScattering *scattering)
81 isl_map *map = isl_map_from_cloog_scattering(scattering);
82 isl_map_print(map, foo, 0, ISL_FORMAT_EXT_POLYLIB);
86 void cloog_domain_free(CloogDomain * domain)
88 isl_set *set = isl_set_from_cloog_domain(domain);
89 isl_set_free(set);
93 void cloog_scattering_free(CloogScattering *scatt)
95 isl_map *map = isl_map_from_cloog_scattering(scatt);
96 isl_map_free(map);
100 CloogDomain * cloog_domain_copy(CloogDomain * domain)
102 isl_set *set = isl_set_from_cloog_domain(domain);
103 return cloog_domain_from_isl_set(isl_set_copy(set));
108 * cloog_domain_convex function:
109 * Computes the convex hull of domain.
111 CloogDomain *cloog_domain_convex(CloogDomain *domain)
113 isl_set *set = isl_set_from_cloog_domain(domain);
114 set = isl_set_from_basic_set(isl_set_convex_hull(isl_set_copy(set)));
115 return cloog_domain_from_isl_set(set);
120 * cloog_domain_simple_convex:
121 * Given a list (union) of polyhedra, this function returns a "simple"
122 * convex hull of this union. In particular, the constraints of the
123 * the returned polyhedron consist of (parametric) lower and upper
124 * bounds on individual variables and constraints that appear in the
125 * original polyhedra.
127 CloogDomain *cloog_domain_simple_convex(CloogDomain *domain)
129 struct isl_basic_set *hull;
130 isl_set *set = isl_set_from_cloog_domain(domain);
132 if (cloog_domain_isconvex(domain))
133 return cloog_domain_copy(domain);
135 hull = isl_set_bounded_simple_hull(isl_set_copy(set));
136 return cloog_domain_from_isl_set(isl_set_from_basic_set(hull));
141 * cloog_domain_simplify function:
142 * Given two polyhedral domains (dom1) and (dom2),
143 * this function finds the largest domain set (or the smallest list
144 * of non-redundant constraints), that when intersected with polyhedral
145 * domain (dom2) equals (dom1)intersect(dom2). The output is a new CloogDomain
146 * structure with a polyhedral domain with the "redundant" constraints removed.
147 * NB: the second domain is required not to be a union.
149 CloogDomain *cloog_domain_simplify(CloogDomain *dom1, CloogDomain *dom2)
151 isl_set *set1 = isl_set_from_cloog_domain(dom1);
152 isl_set *set2 = isl_set_from_cloog_domain(dom2);
153 set1 = isl_set_gist(isl_set_copy(set1), isl_set_copy(set2));
154 return cloog_domain_from_isl_set(set1);
159 * cloog_domain_union function:
160 * This function returns a new polyhedral domain which is the union of
161 * two polyhedral domains (dom1) U (dom2).
162 * Frees dom1 and dom2;
164 CloogDomain *cloog_domain_union(CloogDomain *dom1, CloogDomain *dom2)
166 isl_set *set1 = isl_set_from_cloog_domain(dom1);
167 isl_set *set2 = isl_set_from_cloog_domain(dom2);
168 set1 = isl_set_union(set1, set2);
169 return cloog_domain_from_isl_set(set1);
175 * cloog_domain_intersection function:
176 * This function returns a new polyhedral domain which is the intersection of
177 * two polyhedral domains (dom1) \cap (dom2).
179 CloogDomain *cloog_domain_intersection(CloogDomain *dom1, CloogDomain *dom2)
181 isl_set *set1 = isl_set_from_cloog_domain(dom1);
182 isl_set *set2 = isl_set_from_cloog_domain(dom2);
183 set1 = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
184 return cloog_domain_from_isl_set(set1);
189 * cloog_domain_difference function:
190 * Returns the set difference domain \ minus.
192 CloogDomain *cloog_domain_difference(CloogDomain *domain, CloogDomain *minus)
194 isl_set *set1 = isl_set_from_cloog_domain(domain);
195 isl_set *set2 = isl_set_from_cloog_domain(minus);
196 set1 = isl_set_subtract(isl_set_copy(set1), isl_set_copy(set2));
197 return cloog_domain_from_isl_set(set1);
202 * cloog_domain_sort function:
203 * This function topologically sorts (nb_doms) domains. Here (doms) is an
204 * array of pointers to CloogDomains, (nb_doms) is the number of domains,
205 * (level) is the level to consider for partial ordering (nb_par) is the
206 * parameter space dimension, (permut) if not NULL, is an array of (nb_doms)
207 * integers that contains a permutation specification after call in order to
208 * apply the topological sorting.
210 void cloog_domain_sort(CloogDomain **doms, unsigned nb_doms, unsigned level,
211 int *permut)
213 int i, j, k, cmp;
214 struct isl_ctx *ctx;
215 unsigned char **follows;
216 isl_set *set_i, *set_j;
217 isl_basic_set *bset_i, *bset_j;
219 if (!nb_doms)
220 return;
221 set_i = isl_set_from_cloog_domain(doms[0]);
222 ctx = isl_set_get_ctx(set_i);
223 for (i = 0; i < nb_doms; i++) {
224 set_i = isl_set_from_cloog_domain(doms[i]);
225 assert(isl_set_n_basic_set(set_i) == 1);
228 follows = isl_alloc_array(ctx, unsigned char *, nb_doms);
229 assert(follows);
230 for (i = 0; i < nb_doms; ++i) {
231 follows[i] = isl_alloc_array(ctx, unsigned char, nb_doms);
232 assert(follows[i]);
233 for (j = 0; j < nb_doms; ++j)
234 follows[i][j] = 0;
237 for (i = 1; i < nb_doms; ++i) {
238 for (j = 0; j < i; ++j) {
239 if (follows[i][j] || follows[j][i])
240 continue;
241 set_i = isl_set_from_cloog_domain(doms[i]);
242 set_j = isl_set_from_cloog_domain(doms[j]);
243 bset_i = isl_set_copy_basic_set(set_i);
244 bset_j = isl_set_copy_basic_set(set_j);
245 cmp = isl_basic_set_compare_at(bset_i, bset_j, level-1);
246 isl_basic_set_free(bset_i);
247 isl_basic_set_free(bset_j);
248 if (!cmp)
249 continue;
250 if (cmp > 0) {
251 follows[i][j] = 1;
252 for (k = 0; k < i; ++k)
253 follows[i][k] |= follows[j][k];
254 } else {
255 follows[j][i] = 1;
256 for (k = 0; k < i; ++k)
257 follows[k][i] |= follows[k][j];
262 for (i = 0, j = 0; i < nb_doms; j = (j + 1) % nb_doms) {
263 for (k = 0; k < nb_doms; ++k)
264 if (follows[j][k])
265 break;
266 if (k < nb_doms)
267 continue;
268 for (k = 0; k < nb_doms; ++k)
269 follows[k][j] = 0;
270 follows[j][j] = 1;
271 permut[i] = 1 + j;
272 ++i;
275 for (i = 0; i < nb_doms; ++i)
276 free(follows[i]);
277 free(follows);
282 * Check whether there is or may be any value of dom1 at the given level
283 * that is greater than or equal to a value of dom2 at the same level.
285 * Return
286 * 1 is there is or may be a greater-than pair.
287 * 0 if there is no greater-than pair, but there may be an equal-to pair
288 * -1 if there is definitely no such pair
290 int cloog_domain_follows(CloogDomain *dom1, CloogDomain *dom2, unsigned level)
292 isl_set *set1 = isl_set_from_cloog_domain(dom1);
293 isl_set *set2 = isl_set_from_cloog_domain(dom2);
294 int follows;
296 follows = isl_set_follows_at(set1, set2, level - 1);
297 assert(follows >= -1);
299 return follows;
304 * cloog_domain_empty function:
305 * Returns an empty domain of the same dimensions as template.
307 CloogDomain *cloog_domain_empty(CloogDomain *template)
309 isl_set *set = isl_set_from_cloog_domain(template);
310 return cloog_domain_from_isl_set(isl_set_empty_like(set));
315 * Return 1 if the specified dimension has both an upper and a lower bound.
317 int cloog_domain_is_bounded(CloogDomain *dom, unsigned level)
319 isl_set *set = isl_set_from_cloog_domain(dom);
320 return isl_set_dim_is_bounded(set, isl_dim_set, level - 1);
324 /******************************************************************************
325 * Structure display function *
326 ******************************************************************************/
330 * cloog_domain_print_structure :
331 * this function is a more human-friendly way to display the CloogDomain data
332 * structure, it only shows the constraint system and includes an indentation
333 * level (level) in order to work with others print_structure functions.
335 void cloog_domain_print_structure(FILE *file, CloogDomain *domain, int level,
336 const char *name)
338 int i ;
339 isl_set *set = isl_set_from_cloog_domain(domain);
341 /* Go to the right level. */
342 for (i = 0; i < level; i++)
343 fprintf(file, "|\t");
345 if (!set) {
346 fprintf(file, "+-- Null CloogDomain\n");
347 return;
349 fprintf(file, "+-- %s\n", name);
350 for (i = 0; i < level+1; ++i)
351 fprintf(file, "|\t");
353 isl_set_print(set, file, 0, ISL_FORMAT_ISL);
355 fprintf(file, "\n");
359 /******************************************************************************
360 * Memory deallocation function *
361 ******************************************************************************/
364 void cloog_domain_list_free(CloogDomainList *list)
366 CloogDomainList *next;
368 for ( ; list; list = next) {
369 next = list->next;
370 cloog_domain_free(list->domain);
371 free(list);
377 * cloog_scattering_list_free function:
378 * This function frees the allocated memory for a CloogScatteringList structure.
380 void cloog_scattering_list_free(CloogScatteringList *list)
382 while (list != NULL) {
383 CloogScatteringList *temp = list->next;
384 isl_map *map = isl_map_from_cloog_scattering(list->scatt);
385 isl_map_free(map);
386 free(list);
387 list = temp;
392 /******************************************************************************
393 * Reading function *
394 ******************************************************************************/
398 * cloog_domain_read_context function:
399 * Read parameter domain.
401 CloogDomain *cloog_domain_read_context(CloogState *state, FILE *input)
403 struct isl_ctx *ctx = state->backend->ctx;
404 isl_set *set;
406 set = isl_set_read_from_file(ctx, input);
407 set = isl_set_move_dims(set, isl_dim_param, 0,
408 isl_dim_set, 0, isl_set_dim(set, isl_dim_set));
410 return cloog_domain_from_isl_set(set);
415 * cloog_domain_from_context
416 * Reinterpret context by turning parameters into variables.
418 CloogDomain *cloog_domain_from_context(CloogDomain *context)
420 isl_set *set = isl_set_from_cloog_domain(context);
422 set = isl_set_move_dims(set, isl_dim_set, 0,
423 isl_dim_param, 0, isl_set_dim(set, isl_dim_param));
425 return cloog_domain_from_isl_set(set);
430 * cloog_domain_union_read function:
431 * This function reads a union of polyhedra into a file (input) and
432 * returns a pointer to a CloogDomain containing the read information.
434 CloogDomain *cloog_domain_union_read(CloogState *state,
435 FILE *input, int nb_parameters)
437 struct isl_ctx *ctx = state->backend->ctx;
438 struct isl_set *set;
440 set = isl_set_read_from_file(ctx, input);
441 if (isl_set_dim(set, isl_dim_param) != nb_parameters) {
442 int dim = isl_set_dim(set, isl_dim_set);
443 set = isl_set_move_dims(set, isl_dim_param, 0,
444 isl_dim_set, dim - nb_parameters, nb_parameters);
446 return cloog_domain_from_isl_set(set);
451 * cloog_domain_read_scattering function:
452 * This function reads in a scattering function from the file input.
454 * We try to read the scattering relation as a map, but if it is
455 * specified in the original PolyLib format, then isl_map_read_from_file
456 * will treat the input as a set return a map with zero input dimensions.
457 * In this case, we need to decompose the set into a map from
458 * scattering dimensions to domain dimensions and then invert the
459 * resulting map.
461 CloogScattering *cloog_domain_read_scattering(CloogDomain *domain, FILE *input)
463 isl_set *set = isl_set_from_cloog_domain(domain);
464 isl_ctx *ctx = isl_set_get_ctx(set);
465 struct isl_map *scat;
466 unsigned nparam;
467 unsigned dim;
468 unsigned n_scat;
470 dim = isl_set_dim(set, isl_dim_set);
471 nparam = isl_set_dim(set, isl_dim_param);
472 scat = isl_map_read_from_file(ctx, input);
473 if (isl_map_dim(scat, isl_dim_param) != nparam) {
474 int n_out = isl_map_dim(scat, isl_dim_out);
475 scat = isl_map_move_dims(scat, isl_dim_param, 0,
476 isl_dim_out, n_out - nparam, nparam);
478 if (isl_map_dim(scat, isl_dim_in) != dim) {
479 n_scat = isl_map_dim(scat, isl_dim_out) - dim;
480 scat = isl_map_move_dims(scat, isl_dim_in, 0,
481 isl_dim_out, n_scat, dim);
483 return cloog_scattering_from_isl_map(scat);
486 /******************************************************************************
487 * CloogMatrix Reading function *
488 ******************************************************************************/
491 * isl_constraint_read_from_matrix:
492 * Convert a single line of a matrix to a isl_constraint.
493 * Returns a pointer to the constraint if successful; NULL otherwise.
495 static struct isl_constraint *isl_constraint_read_from_matrix(
496 struct isl_space *dim, cloog_int_t *row)
498 struct isl_constraint *constraint;
499 int j;
500 int nvariables = isl_space_dim(dim, isl_dim_set);
501 int nparam = isl_space_dim(dim, isl_dim_param);
502 isl_local_space *ls = isl_local_space_from_space(dim);
504 if (cloog_int_is_zero(row[0]))
505 constraint = isl_equality_alloc(ls);
506 else
507 constraint = isl_inequality_alloc(ls);
509 for (j = 0; j < nvariables; ++j)
510 isl_constraint_set_coefficient(constraint, isl_dim_out, j,
511 row[1 + j]);
513 for (j = 0; j < nparam; ++j)
514 isl_constraint_set_coefficient(constraint, isl_dim_param, j,
515 row[1 + nvariables + j]);
517 isl_constraint_set_constant(constraint, row[1 + nvariables + nparam]);
519 return constraint;
523 * isl_basic_set_read_from_matrix:
524 * Convert matrix to basic_set. The matrix contains nparam parameter columns.
525 * Returns a pointer to the basic_set if successful; NULL otherwise.
527 static struct isl_basic_set *isl_basic_set_read_from_matrix(struct isl_ctx *ctx,
528 CloogMatrix* matrix, int nparam)
530 struct isl_space *dim;
531 struct isl_basic_set *bset;
532 int i;
533 unsigned nrows, ncolumns;
535 nrows = matrix->NbRows;
536 ncolumns = matrix->NbColumns;
537 int nvariables = ncolumns - 2 - nparam;
539 dim = isl_space_set_alloc(ctx, nparam, nvariables);
541 bset = isl_basic_set_universe(isl_space_copy(dim));
543 for (i = 0; i < nrows; ++i) {
544 cloog_int_t *row = matrix->p[i];
545 struct isl_constraint *constraint =
546 isl_constraint_read_from_matrix(isl_space_copy(dim), row);
547 bset = isl_basic_set_add_constraint(bset, constraint);
550 isl_space_free(dim);
552 return bset;
556 * cloog_domain_from_cloog_matrix:
557 * Create a CloogDomain containing the constraints described in matrix.
558 * nparam is the number of parameters contained in the domain.
559 * Returns a pointer to the CloogDomain if successful; NULL otherwise.
561 CloogDomain *cloog_domain_from_cloog_matrix(CloogState *state,
562 CloogMatrix *matrix, int nparam)
564 struct isl_ctx *ctx = state->backend->ctx;
565 struct isl_basic_set *bset;
567 bset = isl_basic_set_read_from_matrix(ctx, matrix, nparam);
569 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
573 * cloog_scattering_from_cloog_matrix:
574 * Create a CloogScattering containing the constraints described in matrix.
575 * nparam is the number of parameters contained in the domain.
576 * Returns a pointer to the CloogScattering if successful; NULL otherwise.
578 CloogScattering *cloog_scattering_from_cloog_matrix(CloogState *state,
579 CloogMatrix *matrix, int nb_scat, int nb_par)
581 struct isl_ctx *ctx = state->backend->ctx;
582 struct isl_basic_set *bset;
583 struct isl_basic_map *scat;
584 struct isl_space *dims;
585 unsigned dim;
587 bset = isl_basic_set_read_from_matrix(ctx, matrix, nb_par);
588 dim = isl_basic_set_n_dim(bset) - nb_scat;
589 dims = isl_space_alloc(ctx, nb_par, nb_scat, dim);
591 scat = isl_basic_map_from_basic_set(bset, dims);
592 scat = isl_basic_map_reverse(scat);
593 return cloog_scattering_from_isl_map(isl_map_from_basic_map(scat));
597 /******************************************************************************
598 * Processing functions *
599 ******************************************************************************/
602 #ifdef OSL_SUPPORT
604 * Converts an openscop relation to a CLooG domain.
605 * \param[in,out] state CLooG state.
606 * \param[in] relation OpenScop relation to convert.
607 * \return A new CloogDomain corresponding to the input OpenScop relation.
609 CloogDomain *cloog_domain_from_osl_relation(CloogState *state,
610 osl_relation_p relation) {
611 char *str;
612 struct isl_ctx *ctx = state->backend->ctx;
613 isl_set *set;
614 CloogDomain *domain = NULL;
616 if (relation != NULL) {
617 if (relation->precision != OSL_PRECISION_MP)
618 cloog_die("Non-GMP precision is not supported yet.\n");
620 str = osl_relation_spprint_polylib(relation, NULL);
621 set = isl_set_read_from_str(ctx, str);
622 free(str);
624 domain = cloog_domain_from_isl_set(set);
627 return domain;
632 * Converts an openscop scattering relation to a CLooG scattering.
633 * \param[in,out] state CLooG state.
634 * \param[in] relation OpenScop relation to convert.
635 * \return A new CloogScattering corresponding to the input OpenScop relation.
637 CloogScattering *cloog_scattering_from_osl_relation(CloogState *state,
638 osl_relation_p relation) {
639 char *str;
640 struct isl_ctx *ctx = state->backend->ctx;
641 isl_map *map;
642 CloogScattering *scattering = NULL;
644 if (relation != NULL) {
645 if (relation->precision != OSL_PRECISION_MP)
646 cloog_die("Non-GMP precision is not supported yet.\n");
648 if (relation->type != OSL_TYPE_SCATTERING)
649 cloog_die("Cannot convert a non-scattering relation to a scattering.\n");
651 str = osl_relation_spprint_polylib(relation, NULL);
652 map = isl_map_read_from_str(ctx, str);
653 free(str);
655 scattering = cloog_scattering_from_isl_map(map);
658 return scattering;
660 #endif
663 * cloog_domain_isempty function:
665 int cloog_domain_isempty(CloogDomain *domain)
667 isl_set *set = isl_set_from_cloog_domain(domain);
668 return isl_set_is_empty(set);
673 * cloog_domain_universe function:
674 * This function returns the complete dim-dimensional space.
676 CloogDomain *cloog_domain_universe(CloogState *state, unsigned dim)
678 struct isl_space *dims;
679 struct isl_basic_set *bset;
681 dims = isl_space_set_alloc(state->backend->ctx, 0, dim);
682 bset = isl_basic_set_universe(dims);
683 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
688 * cloog_domain_project function:
689 * This function returns the projection of
690 * (domain) on the (level) first dimensions (i.e. outer loops).
692 CloogDomain *cloog_domain_project(CloogDomain *domain, int level)
694 isl_set *set = isl_set_from_cloog_domain(domain);
695 set = isl_set_remove_dims(isl_set_copy(set), isl_dim_set,
696 level, isl_set_n_dim(set) - level);
697 set = isl_set_compute_divs(set);
698 if (level > 0)
699 set = isl_set_remove_divs_involving_dims(set,
700 isl_dim_set, level - 1, 1);
701 return cloog_domain_from_isl_set(set);
706 * cloog_domain_extend function:
707 * This function returns the (domain) given as input with (dim)
708 * dimensions and (nb_par) parameters.
709 * This function does not free (domain), and returns a new CloogDomain.
711 CloogDomain *cloog_domain_extend(CloogDomain *domain, int dim)
713 isl_set *set = isl_set_from_cloog_domain(domain);
714 int n = isl_set_dim(set, isl_dim_set);
715 set = isl_set_add_dims(isl_set_copy(set), isl_dim_set, dim - n);
716 return cloog_domain_from_isl_set(set);
721 * cloog_domain_never_integral function:
722 * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0.
723 * There is no need to check for such constraints explicitly for the isl
724 * backend.
726 int cloog_domain_never_integral(CloogDomain * domain)
728 isl_set *set = isl_set_from_cloog_domain(domain);
729 return isl_set_is_empty(set);
734 * Check whether the loop at "level" is executed at most once.
735 * We construct a map that maps all remaining variables to this iterator
736 * and check whether this map is single valued.
738 * Alternatively, we could have mapped the domain through a mapping
739 * [p] -> { [..., i] -> [..., i'] : i' > i }
740 * and then taken the intersection of the original domain and the transformed
741 * domain. If this intersection is empty, then the corresponding
742 * loop is executed at most once.
744 int cloog_domain_is_otl(CloogDomain *domain, int level)
746 int otl;
747 isl_set *set = isl_set_from_cloog_domain(domain);
748 isl_map *map;
750 map = isl_map_from_domain(isl_set_copy(set));
751 map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_in, level - 1, 1);
752 otl = isl_map_is_single_valued(map);
753 isl_map_free(map);
755 return otl;
760 * cloog_domain_stride function:
761 * This function finds the stride imposed to unknown with the column number
762 * 'strided_level' in order to be integral. For instance, if we have a
763 * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral
764 * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to
765 * the unknown i. The function returns the imposed stride in a parameter field.
766 * - domain is the set of constraint we have to consider,
767 * - strided_level is the column number of the unknown for which a stride have
768 * to be found,
769 * - looking_level is the column number of the unknown that impose a stride to
770 * the first unknown.
771 * - stride is the stride that is returned back as a function parameter.
772 * - offset is the value of the constant c if the condition is of the shape
773 * (i + c)%s = 0, s being the stride.
775 void cloog_domain_stride(CloogDomain *domain, int strided_level,
776 cloog_int_t *stride, cloog_int_t *offset)
778 isl_set *set = isl_set_from_cloog_domain(domain);
779 isl_set_dim_residue_class(set, strided_level - 1, stride, offset);
780 if (!isl_int_is_zero(*offset))
781 isl_int_sub(*offset, *stride, *offset);
782 return;
786 struct cloog_can_stride {
787 int level;
788 int can_stride;
791 static int constraint_can_stride(__isl_take isl_constraint *c, void *user)
793 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
794 int i;
795 isl_int v;
796 unsigned n_div;
798 if (isl_constraint_is_equality(c)) {
799 isl_constraint_free(c);
800 return 0;
803 isl_int_init(v);
804 isl_constraint_get_coefficient(c, isl_dim_set, ccs->level - 1, &v);
805 if (isl_int_is_pos(v)) {
806 n_div = isl_constraint_dim(c, isl_dim_div);
807 for (i = 0; i < n_div; ++i) {
808 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
809 if (!isl_int_is_zero(v))
810 break;
812 if (i < n_div)
813 ccs->can_stride = 0;
815 isl_int_clear(v);
816 isl_constraint_free(c);
818 return 0;
821 static int basic_set_can_stride(__isl_take isl_basic_set *bset, void *user)
823 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
824 int r;
826 r = isl_basic_set_foreach_constraint(bset, constraint_can_stride, ccs);
827 isl_basic_set_free(bset);
828 return r;
833 * Return 1 if CLooG is allowed to perform stride detection on level "level"
834 * and 0 otherwise.
835 * Currently, stride detection is only allowed when none of the lower
836 * bound constraints involve any existentially quantified variables.
837 * The reason is that the current isl interface does not make it
838 * easy to construct an integer division that depends on other integer
839 * divisions.
840 * By not allowing existentially quantified variables in the constraints,
841 * we can ignore them in cloog_domain_stride_lower_bound.
843 int cloog_domain_can_stride(CloogDomain *domain, int level)
845 struct cloog_can_stride ccs = { level, 1 };
846 isl_set *set = isl_set_from_cloog_domain(domain);
847 int r;
848 r = isl_set_foreach_basic_set(set, basic_set_can_stride, &ccs);
849 assert(r == 0);
850 return ccs.can_stride;
854 struct cloog_stride_lower {
855 int level;
856 CloogStride *stride;
857 isl_set *set;
858 isl_basic_set *bounds;
861 /* If the given constraint is a lower bound on csl->level, then add
862 * a lower bound to csl->bounds that makes sure that the remainder
863 * of the smallest value on division by csl->stride is equal to csl->offset.
865 * In particular, the given lower bound is of the form
867 * a i + f >= 0
869 * where f may depend on the parameters and other iterators.
870 * The stride is s and the offset is d.
871 * The lower bound -f/a may not satisfy the above condition. In fact,
872 * it may not even be integral. We want to round this value of i up
873 * to the nearest value that satisfies the condition and add the corresponding
874 * lower bound constraint. This nearest value is obtained by rounding
875 * i - d up to the nearest multiple of s.
876 * That is, we first subtract d
878 * i' = -f/a - d
880 * then we round up to the nearest multiple of s
882 * i'' = s * ceil(i'/s)
884 * and finally, we add d again
886 * i''' = i'' + d
888 * and impose the constraint i >= i'''.
890 * We find
892 * i'' = s * ceil((-f - a * d)/(a * s)) = - s * floor((f + a * d)/(a * s))
894 * i >= - s * floor((f + a * d)/(a * s)) + d
896 * or
897 * i + s * floor((f + a * d)/(a * s)) - d >= 0
899 static int constraint_stride_lower(__isl_take isl_constraint *c, void *user)
901 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
902 isl_int v;
903 isl_constraint *bound;
904 isl_aff *b;
906 if (isl_constraint_is_equality(c)) {
907 isl_constraint_free(c);
908 return 0;
911 isl_int_init(v);
912 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
913 if (!isl_int_is_pos(v)) {
914 isl_int_clear(v);
915 isl_constraint_free(c);
917 return 0;
920 b = isl_constraint_get_bound(c, isl_dim_set, csl->level - 1);
922 b = isl_aff_neg(b);
923 b = isl_aff_add_constant(b, csl->stride->offset);
924 b = isl_aff_scale_down(b, csl->stride->stride);
925 b = isl_aff_floor(b);
926 b = isl_aff_scale(b, csl->stride->stride);
927 isl_int_neg(v, csl->stride->offset);
928 b = isl_aff_add_constant(b, v);
929 b = isl_aff_add_coefficient_si(b, isl_dim_in, csl->level - 1, 1);
931 bound = isl_inequality_from_aff(b);
933 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
935 isl_int_clear(v);
936 isl_constraint_free(c);
938 return 0;
941 /* This functions performs essentially the same operation as
942 * constraint_stride_lower, the only difference being that the offset d
943 * is not a constant, but an affine expression in terms of the parameters
944 * and earlier variables. In particular the affine expression is equal
945 * to the coefficients of stride->constraint multiplied by stride->factor.
946 * As in constraint_stride_lower, we add an extra bound
948 * i + s * floor((f + a * d)/(a * s)) - d >= 0
950 * for each lower bound
952 * a i + f >= 0
954 * where d is not the aforementioned affine expression.
956 static int constraint_stride_lower_c(__isl_take isl_constraint *c, void *user)
958 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
959 isl_int v;
960 isl_constraint *bound;
961 isl_constraint *csl_c;
962 isl_aff *d, *b;
964 if (isl_constraint_is_equality(c)) {
965 isl_constraint_free(c);
966 return 0;
969 isl_int_init(v);
970 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
971 if (!isl_int_is_pos(v)) {
972 isl_int_clear(v);
973 isl_constraint_free(c);
975 return 0;
978 csl_c = cloog_constraint_to_isl(csl->stride->constraint);
980 d = isl_constraint_get_aff(csl_c);
981 d = isl_aff_drop_dims(d, isl_dim_div, 0, isl_aff_dim(d, isl_dim_div));
982 d = isl_aff_set_coefficient_si(d, isl_dim_in, csl->level - 1, 0);
983 d = isl_aff_scale(d, csl->stride->factor);
985 b = isl_constraint_get_bound(c, isl_dim_set, csl->level - 1);
987 b = isl_aff_neg(b);
988 b = isl_aff_add(b, isl_aff_copy(d));
989 b = isl_aff_scale_down(b, csl->stride->stride);
990 b = isl_aff_floor(b);
991 b = isl_aff_scale(b, csl->stride->stride);
992 b = isl_aff_sub(b, d);
993 b = isl_aff_add_coefficient_si(b, isl_dim_in, csl->level - 1, 1);
995 bound = isl_inequality_from_aff(b);
997 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
999 isl_int_clear(v);
1000 isl_constraint_free(c);
1002 return 0;
1005 static int basic_set_stride_lower(__isl_take isl_basic_set *bset, void *user)
1007 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
1008 int r;
1010 csl->bounds = isl_basic_set_universe_like(bset);
1011 if (csl->stride->constraint)
1012 r = isl_basic_set_foreach_constraint(bset,
1013 &constraint_stride_lower_c, csl);
1014 else
1015 r = isl_basic_set_foreach_constraint(bset,
1016 &constraint_stride_lower, csl);
1017 bset = isl_basic_set_intersect(bset, csl->bounds);
1018 csl->set = isl_set_union(csl->set, isl_set_from_basic_set(bset));
1020 return r;
1024 * Update the lower bounds at level "level" to the given stride information.
1025 * That is, make sure that the remainder on division by "stride"
1026 * is equal to "offset".
1028 CloogDomain *cloog_domain_stride_lower_bound(CloogDomain *domain, int level,
1029 CloogStride *stride)
1031 struct cloog_stride_lower csl;
1032 isl_set *set = isl_set_from_cloog_domain(domain);
1033 int r;
1035 csl.stride = stride;
1036 csl.level = level;
1037 csl.set = isl_set_empty_like(set);
1039 r = isl_set_foreach_basic_set(set, basic_set_stride_lower, &csl);
1040 assert(r == 0);
1042 cloog_domain_free(domain);
1043 return cloog_domain_from_isl_set(csl.set);
1047 /* Add stride constraint, if any, to domain.
1049 CloogDomain *cloog_domain_add_stride_constraint(CloogDomain *domain,
1050 CloogStride *stride)
1052 isl_constraint *c;
1053 isl_set *set;
1055 if (!stride || !stride->constraint)
1056 return domain;
1058 set = isl_set_from_cloog_domain(domain);
1059 c = isl_constraint_copy(cloog_constraint_to_isl(stride->constraint));
1061 set = isl_set_add_constraint(set, c);
1063 return cloog_domain_from_isl_set(set);
1068 * cloog_domain_lazy_equal function:
1069 * This function returns 1 if the domains given as input are the same, 0 if it
1070 * is unable to decide.
1072 int cloog_domain_lazy_equal(CloogDomain *d1, CloogDomain *d2)
1074 isl_set *set1 = isl_set_from_cloog_domain(d1);
1075 isl_set *set2 = isl_set_from_cloog_domain(d2);
1076 return isl_set_fast_is_equal(set1, set2);
1079 struct cloog_bound_split {
1080 isl_set *set;
1081 int level;
1082 int lower;
1083 int upper;
1086 static int constraint_bound_split(__isl_take isl_constraint *c, void *user)
1088 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1089 isl_int v;
1090 int i;
1091 int handle = 0;
1093 isl_int_init(v);
1094 isl_constraint_get_coefficient(c, isl_dim_set, cbs->level - 1, &v);
1095 if (!cbs->lower && isl_int_is_pos(v))
1096 cbs->lower = handle = 1;
1097 else if (!cbs->upper && isl_int_is_neg(v))
1098 cbs->upper = handle = 1;
1099 if (handle) {
1100 for (i = 0; i < isl_set_dim(cbs->set, isl_dim_param); ++i) {
1101 isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
1102 if (isl_int_is_zero(v))
1103 continue;
1104 cbs->set = isl_set_split_dims(cbs->set,
1105 isl_dim_param, i, 1);
1108 isl_int_clear(v);
1109 isl_constraint_free(c);
1111 return (cbs->lower && cbs->upper) ? -1 : 0;
1114 static int basic_set_bound_split(__isl_take isl_basic_set *bset, void *user)
1116 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1117 int r;
1119 cbs->lower = 0;
1120 cbs->upper = 0;
1121 r = isl_basic_set_foreach_constraint(bset, constraint_bound_split, cbs);
1122 isl_basic_set_free(bset);
1123 return ((!cbs->lower || !cbs->upper) && r < 0) ? -1 : 0;
1127 * Return a union of sets S_i such that the convex hull of "dom",
1128 * when intersected with one the sets S_i, will have an upper and
1129 * lower bound for the dimension at "level" (provided "dom" itself
1130 * has such bounds for the dimensions).
1132 * We currently take a very simple approach. For each of the basic
1133 * sets in "dom" we pick a lower and an upper bound and split the
1134 * range of any parameter involved in these two bounds in a
1135 * nonnegative and a negative part. This ensures that the symbolic
1136 * constant in these two constraints are themselves bounded and
1137 * so there will be at least one upper and one lower bound
1138 * in the convex hull.
1140 CloogDomain *cloog_domain_bound_splitter(CloogDomain *dom, int level)
1142 struct cloog_bound_split cbs;
1143 isl_set *set = isl_set_from_cloog_domain(dom);
1144 int r;
1145 cbs.level = level;
1146 cbs.set = isl_set_universe_like(set);
1147 r = isl_set_foreach_basic_set(set, basic_set_bound_split, &cbs);
1148 assert(r == 0);
1149 return cloog_domain_from_isl_set(cbs.set);
1153 /* Check whether the union of scattering functions over all domains
1154 * is obviously injective.
1156 static int injective_scattering(CloogScatteringList *list)
1158 isl_map *map;
1159 isl_union_map *umap;
1160 int injective;
1161 int i = 0;
1162 char name[30];
1164 if (!list)
1165 return 1;
1167 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1168 snprintf(name, sizeof(name), "S%d", i);
1169 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1170 umap = isl_union_map_from_map(map);
1172 for (list = list->next, ++i; list; list = list->next, ++i) {
1173 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1174 snprintf(name, sizeof(name), "S%d", i);
1175 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1176 umap = isl_union_map_add_map(umap, map);
1179 injective = isl_union_map_plain_is_injective(umap);
1181 isl_union_map_free(umap);
1183 return injective;
1188 * cloog_scattering_lazy_block function:
1189 * This function returns 1 if the two scattering functions s1 and s2 given
1190 * as input are the same (except possibly for the final dimension, where we
1191 * allow a difference of 1), assuming that the domains on which this
1192 * scatterings are applied are the same.
1193 * In fact this function answers the question "can I
1194 * safely consider the two domains as only one with two statements (a block) ?".
1195 * A difference of 1 in the final dimension is only allowed if the
1196 * entire scattering function is injective.
1197 * - s1 and s2 are the two domains to check for blocking,
1198 * - scattering is the linked list of all domains,
1199 * - scattdims is the total number of scattering dimentions.
1201 int cloog_scattering_lazy_block(CloogScattering *s1, CloogScattering *s2,
1202 CloogScatteringList *scattering, int scattdims)
1204 int i;
1205 struct isl_space *dim;
1206 struct isl_map *rel;
1207 struct isl_set *delta;
1208 isl_map *map1 = isl_map_from_cloog_scattering(s1);
1209 isl_map *map2 = isl_map_from_cloog_scattering(s2);
1210 int fixed, block;
1211 isl_int cst;
1212 unsigned n_scat;
1214 n_scat = isl_map_dim(map1, isl_dim_out);
1215 if (n_scat != isl_map_dim(map2, isl_dim_out))
1216 return 0;
1218 dim = isl_map_get_space(map1);
1219 dim = isl_space_map_from_set(isl_space_domain(dim));
1220 rel = isl_map_identity(dim);
1221 rel = isl_map_apply_domain(rel, isl_map_copy(map1));
1222 rel = isl_map_apply_range(rel, isl_map_copy(map2));
1223 delta = isl_map_deltas(rel);
1224 isl_int_init(cst);
1225 for (i = 0; i < n_scat; ++i) {
1226 fixed = isl_set_fast_dim_is_fixed(delta, i, &cst);
1227 if (fixed != 1)
1228 break;
1229 if (isl_int_is_zero(cst))
1230 continue;
1231 if (i + 1 < n_scat)
1232 break;
1233 if (!isl_int_is_one(cst))
1234 break;
1235 if (!injective_scattering(scattering))
1236 break;
1238 block = i >= n_scat;
1239 isl_int_clear(cst);
1240 isl_set_free(delta);
1241 return block;
1246 * cloog_domain_lazy_disjoint function:
1247 * This function returns 1 if the domains given as input are disjoint, 0 if it
1248 * is unable to decide.
1250 int cloog_domain_lazy_disjoint(CloogDomain *d1, CloogDomain *d2)
1252 isl_set *set1 = isl_set_from_cloog_domain(d1);
1253 isl_set *set2 = isl_set_from_cloog_domain(d2);
1254 return isl_set_fast_is_disjoint(set1, set2);
1259 * cloog_scattering_list_lazy_same function:
1260 * This function returns 1 if two domains in the list are the same, 0 if it
1261 * is unable to decide.
1263 int cloog_scattering_list_lazy_same(CloogScatteringList *list)
1265 CloogScatteringList *one, *other;
1266 isl_map *one_map, *other_map;
1268 for (one = list; one; one = one->next) {
1269 one_map = isl_map_from_cloog_scattering(one->scatt);
1270 for (other = one->next; other; other = other->next) {
1271 other_map = isl_map_from_cloog_scattering(other->scatt);
1272 if (isl_map_fast_is_equal(one_map, other_map))
1273 return 1;
1276 return 0;
1279 int cloog_domain_dimension(CloogDomain * domain)
1281 isl_set *set = isl_set_from_cloog_domain(domain);
1282 return isl_set_dim(set, isl_dim_set);
1285 int cloog_domain_parameter_dimension(CloogDomain *domain)
1287 isl_set *set = isl_set_from_cloog_domain(domain);
1288 return isl_set_dim(set, isl_dim_param);
1291 int cloog_scattering_dimension(CloogScattering *scatt, CloogDomain *domain)
1293 isl_map *map = isl_map_from_cloog_scattering(scatt);
1294 return isl_map_dim(map, isl_dim_out);
1297 int cloog_domain_isconvex(CloogDomain * domain)
1299 isl_set *set = isl_set_from_cloog_domain(domain);
1300 return isl_set_n_basic_set(set) <= 1;
1305 * cloog_domain_cut_first function:
1306 * This function splits off and returns the first convex set in the
1307 * union "domain". The remainder of the union is returned in rest.
1308 * The original "domain" itself is destroyed and may not be used
1309 * after a call to this function.
1311 CloogDomain *cloog_domain_cut_first(CloogDomain *domain, CloogDomain **rest)
1313 isl_set *set = isl_set_from_cloog_domain(domain);
1314 struct isl_basic_set *first;
1316 first = isl_set_copy_basic_set(set);
1317 set = isl_set_drop_basic_set(set, first);
1318 *rest = cloog_domain_from_isl_set(set);
1320 return cloog_domain_from_isl_set(isl_set_from_basic_set(first));
1325 * Given a union domain, try to find a simpler representation
1326 * using fewer sets in the union.
1327 * The original "domain" itself is destroyed and may not be used
1328 * after a call to this function.
1330 CloogDomain *cloog_domain_simplify_union(CloogDomain *domain)
1332 isl_set *set = isl_set_from_cloog_domain(domain);
1333 return cloog_domain_from_isl_set(isl_set_coalesce(set));
1338 * cloog_scattering_lazy_isscalar function:
1339 * this function returns 1 if the scattering dimension 'dimension' in the
1340 * scattering 'scatt' is constant.
1341 * If value is not NULL, then it is set to the constant value of dimension.
1343 int cloog_scattering_lazy_isscalar(CloogScattering *scatt, int dimension,
1344 cloog_int_t *value)
1346 isl_map *map = isl_map_from_cloog_scattering(scatt);
1347 return isl_map_fast_is_fixed(map, isl_dim_out, dimension, value);
1352 * cloog_domain_lazy_isconstant function:
1353 * this function returns 1 if the dimension 'dimension' in the
1354 * domain 'domain' is constant.
1355 * If value is not NULL, then it is set to the constant value of dimension.
1357 int cloog_domain_lazy_isconstant(CloogDomain *domain, int dimension,
1358 cloog_int_t *value)
1360 isl_set *set = isl_set_from_cloog_domain(domain);
1361 return isl_set_fast_dim_is_fixed(set, dimension, value);
1366 * cloog_scattering_erase_dimension function:
1367 * this function returns a CloogDomain structure builds from 'domain' where
1368 * we removed the dimension 'dimension' and every constraint involving this
1369 * dimension.
1371 CloogScattering *cloog_scattering_erase_dimension(CloogScattering *scattering,
1372 int dimension)
1374 isl_map *map = isl_map_from_cloog_scattering(scattering);
1375 map = isl_map_remove_dims(isl_map_copy(map), isl_dim_out, dimension, 1);
1376 return cloog_scattering_from_isl_map(map);
1380 * cloog_domain_cube:
1381 * Construct and return a dim-dimensional cube, with values ranging
1382 * between min and max in each dimension.
1384 CloogDomain *cloog_domain_cube(CloogState *state,
1385 int dim, cloog_int_t min, cloog_int_t max)
1387 int i;
1388 struct isl_basic_set *cube;
1389 struct isl_basic_set *interval;
1390 struct isl_basic_set_list *list;
1392 if (dim == 0)
1393 return cloog_domain_universe(state, dim);
1395 interval = isl_basic_set_interval(state->backend->ctx, min, max);
1396 list = isl_basic_set_list_alloc(state->backend->ctx, dim);
1397 for (i = 0; i < dim; ++i)
1398 list = isl_basic_set_list_add(list, isl_basic_set_copy(interval));
1399 isl_basic_set_free(interval);
1400 cube = isl_basic_set_list_product(list);
1401 return cloog_domain_from_isl_set(isl_set_from_basic_set(cube));
1406 * cloog_domain_scatter function:
1407 * This function add the scattering (scheduling) informations to a domain.
1409 CloogDomain *cloog_domain_scatter(CloogDomain *domain, CloogScattering *scatt)
1411 isl_set *set = isl_set_from_cloog_domain(domain);
1412 isl_map *map = isl_map_from_cloog_scattering(scatt);
1414 map = isl_map_reverse(isl_map_copy(map));
1415 map = isl_map_intersect_range(map, set);
1416 set = isl_set_flatten(isl_map_wrap(map));
1417 return cloog_domain_from_isl_set(set);
1420 static int add_domain_from_map(__isl_take isl_map *map, void *user)
1422 isl_space *dim;
1423 const char *name;
1424 CloogDomain *domain;
1425 CloogScattering *scat;
1426 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1428 dim = isl_map_get_space(map);
1429 name = isl_space_get_tuple_name(dim, isl_dim_in);
1430 domain = cloog_domain_from_isl_set(isl_map_domain(isl_map_copy(map)));
1431 scat = cloog_scattering_from_isl_map(map);
1432 *ud = cloog_union_domain_add_domain(*ud, name, domain, scat, NULL);
1433 isl_space_free(dim);
1435 return 0;
1439 * Construct a CloogUnionDomain from an isl_union_map representing
1440 * a global scattering function. The input is a mapping from different
1441 * spaces (different tuple names and possibly different dimensions)
1442 * to a common space. The iteration domains are set to the domains
1443 * in each space. The statement names are set to the names of the
1444 * spaces. The parameter names of the result are set to those of
1445 * the input, but the iterator and scattering dimension names are
1446 * left unspecified.
1448 CloogUnionDomain *cloog_union_domain_from_isl_union_map(
1449 __isl_take isl_union_map *umap)
1451 int i;
1452 int nparam;
1453 isl_space *dim;
1454 CloogUnionDomain *ud;
1456 dim = isl_union_map_get_space(umap);
1457 nparam = isl_space_dim(dim, isl_dim_param);
1459 ud = cloog_union_domain_alloc(nparam);
1461 for (i = 0; i < nparam; ++i) {
1462 const char *s = isl_space_get_dim_name(dim, isl_dim_param, i);
1463 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1465 isl_space_free(dim);
1467 if (isl_union_map_foreach_map(umap, &add_domain_from_map, &ud) < 0) {
1468 isl_union_map_free(umap);
1469 cloog_union_domain_free(ud);
1470 assert(0);
1473 isl_union_map_free(umap);
1475 return ud;
1478 static int count_same_name(__isl_keep isl_space *dim,
1479 enum isl_dim_type type, unsigned pos, const char *name)
1481 enum isl_dim_type t;
1482 unsigned p, s;
1483 int count = 0;
1484 int len = strlen(name);
1486 for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) {
1487 s = t == type ? pos : isl_space_dim(dim, t);
1488 for (p = 0; p < s; ++p) {
1489 const char *n = isl_space_get_dim_name(dim, t, p);
1490 if (n && !strncmp(n, name, len))
1491 count++;
1494 return count;
1497 static CloogUnionDomain *add_domain(__isl_take isl_set *set, CloogUnionDomain *ud)
1499 int i, nvar;
1500 isl_ctx *ctx;
1501 isl_space *dim;
1502 char buffer[20];
1503 const char *name;
1504 CloogDomain *domain;
1506 ctx = isl_set_get_ctx(set);
1507 dim = isl_set_get_space(set);
1508 name = isl_space_get_tuple_name(dim, isl_dim_set);
1509 set = isl_set_flatten(set);
1510 set = isl_set_set_tuple_name(set, NULL);
1511 domain = cloog_domain_from_isl_set(set);
1512 ud = cloog_union_domain_add_domain(ud, name, domain, NULL, NULL);
1514 nvar = isl_space_dim(dim, isl_dim_set);
1515 for (i = 0; i < nvar; ++i) {
1516 char *long_name = NULL;
1517 int n;
1519 name = isl_space_get_dim_name(dim, isl_dim_set, i);
1520 if (!name) {
1521 snprintf(buffer, sizeof(buffer), "i%d", i);
1522 name = buffer;
1524 n = count_same_name(dim, isl_dim_set, i, name);
1525 if (n) {
1526 int size = strlen(name) + 10;
1527 long_name = isl_alloc_array(ctx, char, size);
1528 if (!long_name)
1529 cloog_die("memory overflow.\n");
1530 snprintf(long_name, size, "%s_%d", name, n);
1531 name = long_name;
1533 ud = cloog_union_domain_set_name(ud, CLOOG_ITER, i, name);
1534 free(long_name);
1536 isl_space_free(dim);
1538 return ud;
1542 * Construct a CloogUnionDomain from an isl_set.
1543 * The statement names are set to the names of the
1544 * spaces. The parameter and iterator names of the result are set to those of
1545 * the input, but the scattering dimension names are left unspecified.
1547 CloogUnionDomain *cloog_union_domain_from_isl_set(
1548 __isl_take isl_set *set)
1550 int i;
1551 int nparam;
1552 isl_space *dim;
1553 CloogUnionDomain *ud;
1555 dim = isl_set_get_space(set);
1556 nparam = isl_space_dim(dim, isl_dim_param);
1558 ud = cloog_union_domain_alloc(nparam);
1560 for (i = 0; i < nparam; ++i) {
1561 const char *s = isl_space_get_dim_name(dim, isl_dim_param, i);
1562 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1564 isl_space_free(dim);
1566 ud = add_domain(set, ud);
1568 return ud;
1571 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
1572 static void Euclid(cloog_int_t a, cloog_int_t b,
1573 cloog_int_t *x, cloog_int_t *y, cloog_int_t *g)
1575 cloog_int_t c, d, e, f, tmp;
1577 cloog_int_init(c);
1578 cloog_int_init(d);
1579 cloog_int_init(e);
1580 cloog_int_init(f);
1581 cloog_int_init(tmp);
1582 cloog_int_abs(c, a);
1583 cloog_int_abs(d, b);
1584 cloog_int_set_si(e, 1);
1585 cloog_int_set_si(f, 0);
1586 while (cloog_int_is_pos(d)) {
1587 cloog_int_tdiv_q(tmp, c, d);
1588 cloog_int_mul(tmp, tmp, f);
1589 cloog_int_sub(e, e, tmp);
1590 cloog_int_tdiv_q(tmp, c, d);
1591 cloog_int_mul(tmp, tmp, d);
1592 cloog_int_sub(c, c, tmp);
1593 cloog_int_swap(c, d);
1594 cloog_int_swap(e, f);
1596 cloog_int_set(*g, c);
1597 if (cloog_int_is_zero(a))
1598 cloog_int_set_si(*x, 0);
1599 else if (cloog_int_is_pos(a))
1600 cloog_int_set(*x, e);
1601 else cloog_int_neg(*x, e);
1602 if (cloog_int_is_zero(b))
1603 cloog_int_set_si(*y, 0);
1604 else {
1605 cloog_int_mul(tmp, a, *x);
1606 cloog_int_sub(tmp, c, tmp);
1607 cloog_int_divexact(*y, tmp, b);
1609 cloog_int_clear(c);
1610 cloog_int_clear(d);
1611 cloog_int_clear(e);
1612 cloog_int_clear(f);
1613 cloog_int_clear(tmp);
1616 /* Construct a CloogStride from the given constraint for the given level,
1617 * if possible.
1618 * We first compute the gcd of the coefficients of the existentially
1619 * quantified variables and then remove any common factors it has
1620 * with the coefficient at the given level.
1621 * The result is the value of the stride and if it is not one,
1622 * then it is possible to construct a CloogStride.
1623 * The constraint leading to the stride is stored in the CloogStride
1624 * as well a value (factor) such that the product of this value
1625 * and the coefficient at the given level is equal to -1 modulo the stride.
1627 static CloogStride *construct_stride(isl_constraint *c, int level)
1629 int i, n, sign;
1630 isl_int v, m, gcd, stride, factor;
1631 CloogStride *s;
1633 if (!c)
1634 return NULL;
1636 isl_int_init(v);
1637 isl_int_init(m);
1638 isl_int_init(gcd);
1639 isl_int_init(factor);
1640 isl_int_init(stride);
1642 isl_constraint_get_coefficient(c, isl_dim_set, level - 1, &v);
1643 sign = isl_int_sgn(v);
1644 isl_int_abs(m, v);
1646 isl_int_set_si(gcd, 0);
1647 n = isl_constraint_dim(c, isl_dim_div);
1648 for (i = 0; i < n; ++i) {
1649 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
1650 isl_int_gcd(gcd, gcd, v);
1653 isl_int_gcd(v, m, gcd);
1654 isl_int_divexact(stride, gcd, v);
1656 if (isl_int_is_zero(stride) || isl_int_is_one(stride))
1657 s = NULL;
1658 else {
1659 Euclid(m, stride, &factor, &v, &gcd);
1660 if (sign > 0)
1661 isl_int_neg(factor, factor);
1663 c = isl_constraint_copy(c);
1664 s = cloog_stride_alloc_from_constraint(stride,
1665 cloog_constraint_from_isl_constraint(c), factor);
1668 isl_int_clear(stride);
1669 isl_int_clear(factor);
1670 isl_int_clear(gcd);
1671 isl_int_clear(m);
1672 isl_int_clear(v);
1674 return s;
1677 struct cloog_isl_find_stride_data {
1678 int level;
1679 CloogStride *stride;
1682 /* Check if the given constraint can be used to derive
1683 * a stride on the iterator identified by data->level.
1684 * We first check that there are some existentially quantified variables
1685 * and that the coefficient at data->level is non-zero.
1686 * Then we call construct_stride for further checks and the actual
1687 * construction of the CloogStride.
1689 static int find_stride(__isl_take isl_constraint *c, void *user)
1691 struct cloog_isl_find_stride_data *data;
1692 int n;
1693 isl_int v;
1695 data = (struct cloog_isl_find_stride_data *)user;
1697 if (data->stride) {
1698 isl_constraint_free(c);
1699 return 0;
1702 n = isl_constraint_dim(c, isl_dim_div);
1703 if (n == 0) {
1704 isl_constraint_free(c);
1705 return 0;
1708 isl_int_init(v);
1710 isl_constraint_get_coefficient(c, isl_dim_set, data->level - 1, &v);
1711 if (!isl_int_is_zero(v))
1712 data->stride = construct_stride(c, data->level);
1714 isl_int_clear(v);
1716 isl_constraint_free(c);
1718 return 0;
1721 /* Check if the given list of domains has a common stride on the given level.
1722 * If so, return a pointer to a CloogStride object. If not, return NULL.
1724 * We project out all later variables, take the union and compute
1725 * the affine hull of the union. Then we check the (equality)
1726 * constraints in this affine hull for imposing a stride.
1728 CloogStride *cloog_domain_list_stride(CloogDomainList *list, int level)
1730 struct cloog_isl_find_stride_data data = { level, NULL };
1731 isl_set *set;
1732 isl_basic_set *aff;
1733 int first = level;
1734 int n;
1735 int r;
1737 set = isl_set_from_cloog_domain(list->domain);
1738 n = isl_set_dim(set, isl_dim_set) - first;
1739 set = isl_set_project_out(isl_set_copy(set), isl_dim_set, first, n);
1741 for (list = list->next; list; list = list->next) {
1742 isl_set *set_i = isl_set_from_cloog_domain(list->domain);
1743 n = isl_set_dim(set_i, isl_dim_set) - first;
1744 set_i = isl_set_project_out(isl_set_copy(set_i),
1745 isl_dim_set, first, n);
1746 set = isl_set_union(set, set_i);
1748 aff = isl_set_affine_hull(set);
1750 r = isl_basic_set_foreach_constraint(aff, &find_stride, &data);
1751 assert(r == 0);
1753 isl_basic_set_free(aff);
1755 return data.stride;
1758 struct cloog_can_unroll {
1759 int can_unroll;
1760 int level;
1761 isl_constraint *c;
1762 isl_set *set;
1763 isl_int *n;
1768 * Check if the given lower bound can be used for unrolling
1769 * and, if so, return the unrolling factor/trip count in *v.
1770 * If the lower bound involves any existentially quantified
1771 * variables, we currently punt.
1772 * Otherwise we compute the maximal value of (i - ceil(l) + 1),
1773 * with l the given lower bound and i the iterator identified by level.
1775 static int is_valid_unrolling_lower_bound(struct cloog_can_unroll *ccu,
1776 __isl_keep isl_constraint *c, isl_int *v)
1778 unsigned n_div;
1779 isl_aff *aff;
1780 enum isl_lp_result res;
1782 n_div = isl_constraint_dim(c, isl_dim_div);
1783 if (isl_constraint_involves_dims(c, isl_dim_div, 0, n_div))
1784 return 0;
1786 aff = isl_constraint_get_bound(c, isl_dim_set, ccu->level - 1);
1787 aff = isl_aff_ceil(aff);
1788 aff = isl_aff_neg(aff);
1789 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, ccu->level - 1, 1);
1790 res = isl_set_max(ccu->set, aff, v);
1791 isl_aff_free(aff);
1793 if (res == isl_lp_unbounded)
1794 return 0;
1796 assert(res == isl_lp_ok);
1798 cloog_int_add_ui(*v, *v, 1);
1800 return 1;
1804 /* Check if we can unroll based on the given constraint.
1805 * Only lower bounds can be used.
1806 * Record it if it turns out to be usable and if we haven't recorded
1807 * any other constraint already.
1809 static int constraint_can_unroll(__isl_take isl_constraint *c, void *user)
1811 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1812 isl_int v;
1813 isl_int count;
1815 isl_int_init(v);
1816 isl_int_init(count);
1817 isl_constraint_get_coefficient(c, isl_dim_set, ccu->level - 1, &v);
1818 if (isl_int_is_pos(v) &&
1819 is_valid_unrolling_lower_bound(ccu, c, &count) &&
1820 (!ccu->c || isl_int_lt(count, *ccu->n))) {
1821 isl_constraint_free(ccu->c);
1822 ccu->c = isl_constraint_copy(c);
1823 isl_int_set(*ccu->n, count);
1825 isl_int_clear(count);
1826 isl_int_clear(v);
1827 isl_constraint_free(c);
1829 return 0;
1833 /* Check if we can unroll the domain at the current level.
1834 * If the domain is a union, we cannot. Otherwise, we check the
1835 * constraints.
1837 static int basic_set_can_unroll(__isl_take isl_basic_set *bset, void *user)
1839 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1840 int r = 0;
1842 if (ccu->c || !ccu->can_unroll)
1843 ccu->can_unroll = 0;
1844 else {
1845 bset = isl_basic_set_remove_redundancies(bset);
1846 r = isl_basic_set_foreach_constraint(bset,
1847 &constraint_can_unroll, ccu);
1849 isl_basic_set_free(bset);
1850 return r;
1854 /* Check if we can unroll the given domain at the given level, and
1855 * if so, return the single lower bound in *lb and an upper bound
1856 * on the number of iterations in *n.
1857 * If we cannot unroll, return 0 and set *lb to NULL.
1859 * We can unroll, if we can identify a lower bound on level
1860 * such that the number of iterations is bounded by a constant.
1862 int cloog_domain_can_unroll(CloogDomain *domain, int level, cloog_int_t *n,
1863 CloogConstraint **lb)
1865 isl_set *set = isl_set_from_cloog_domain(domain);
1866 struct cloog_can_unroll ccu = { 1, level, NULL, set, n };
1867 int r;
1869 *lb = NULL;
1870 r = isl_set_foreach_basic_set(set, &basic_set_can_unroll, &ccu);
1871 assert(r == 0);
1872 if (!ccu.c)
1873 ccu.can_unroll = 0;
1874 if (!ccu.can_unroll) {
1875 isl_constraint_free(ccu.c);
1876 return 0;
1879 *lb = cloog_constraint_from_isl_constraint(ccu.c);
1881 return ccu.can_unroll;
1885 /* Fix the iterator i at the given level to l + o,
1886 * where l is prescribed by the constraint lb and o is equal to offset.
1887 * In particular, if lb is the constraint
1889 * a i >= f(j)
1891 * then l = ceil(f(j)/a).
1893 CloogDomain *cloog_domain_fixed_offset(CloogDomain *domain,
1894 int level, CloogConstraint *lb, cloog_int_t offset)
1896 isl_aff *aff;
1897 isl_set *set = isl_set_from_cloog_domain(domain);
1898 isl_constraint *c;
1899 isl_constraint *eq;
1901 c = cloog_constraint_to_isl(lb);
1902 aff = isl_constraint_get_bound(c, isl_dim_set, level - 1);
1903 aff = isl_aff_ceil(aff);
1904 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, level - 1, -1);
1905 aff = isl_aff_add_constant(aff, offset);
1906 eq = isl_equality_from_aff(aff);
1907 set = isl_set_add_constraint(set, eq);
1909 return cloog_domain_from_isl_set(set);