Scattering dimension names from OpenScop scatnames extension
[cloog.git] / source / isl / domain.c
blob054c37b096ea7170644f584add7b6a29c3941372
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/macros.h>
14 #include <osl/relation.h>
15 #endif
17 CloogDomain *cloog_domain_from_isl_set(struct isl_set *set)
19 set = isl_set_detect_equalities(set);
20 set = isl_set_compute_divs(set);
21 return (CloogDomain *)set;
24 __isl_give isl_set *isl_set_from_cloog_domain(CloogDomain *domain)
26 return (isl_set *)domain;
29 CloogScattering *cloog_scattering_from_isl_map(struct isl_map *map)
31 return (CloogScattering *)map;
34 __isl_give isl_map *isl_map_from_cloog_scattering(CloogScattering *scattering)
36 return (isl_map *)scattering;
40 /**
41 * Returns true if each scattering dimension is defined in terms
42 * of the original iterators.
44 int cloog_scattering_fully_specified(CloogScattering *scattering,
45 CloogDomain *domain)
47 isl_map *map = isl_map_from_cloog_scattering(scattering);
48 return isl_map_is_single_valued(map);
52 CloogConstraintSet *cloog_domain_constraints(CloogDomain *domain)
54 isl_basic_set *bset;
55 isl_set *set = isl_set_from_cloog_domain(domain);
56 assert(isl_set_n_basic_set(set) == 1);
57 bset = isl_set_copy_basic_set(set);
58 return cloog_constraint_set_from_isl_basic_set(bset);
62 void cloog_domain_print_constraints(FILE *foo, CloogDomain *domain,
63 int print_number)
65 isl_basic_set *bset;
66 isl_set *set = isl_set_from_cloog_domain(domain);
68 if (print_number)
69 isl_set_print(set, foo, 0, ISL_FORMAT_EXT_POLYLIB);
70 else {
71 assert(isl_set_n_basic_set(set) == 1);
72 bset = isl_set_copy_basic_set(set);
73 isl_basic_set_print(bset, foo,
74 0, NULL, NULL, ISL_FORMAT_POLYLIB);
75 isl_basic_set_free(bset);
80 void cloog_scattering_print_constraints(FILE *foo, CloogScattering *scattering)
82 isl_map *map = isl_map_from_cloog_scattering(scattering);
83 isl_map_print(map, foo, 0, ISL_FORMAT_EXT_POLYLIB);
87 void cloog_domain_free(CloogDomain * domain)
89 isl_set *set = isl_set_from_cloog_domain(domain);
90 isl_set_free(set);
94 void cloog_scattering_free(CloogScattering *scatt)
96 isl_map *map = isl_map_from_cloog_scattering(scatt);
97 isl_map_free(map);
101 CloogDomain * cloog_domain_copy(CloogDomain * domain)
103 isl_set *set = isl_set_from_cloog_domain(domain);
104 return cloog_domain_from_isl_set(isl_set_copy(set));
109 * cloog_domain_convex function:
110 * Computes the convex hull of domain.
112 CloogDomain *cloog_domain_convex(CloogDomain *domain)
114 isl_set *set = isl_set_from_cloog_domain(domain);
115 set = isl_set_from_basic_set(isl_set_convex_hull(isl_set_copy(set)));
116 return cloog_domain_from_isl_set(set);
121 * cloog_domain_simple_convex:
122 * Given a list (union) of polyhedra, this function returns a "simple"
123 * convex hull of this union. In particular, the constraints of the
124 * the returned polyhedron consist of (parametric) lower and upper
125 * bounds on individual variables and constraints that appear in the
126 * original polyhedra.
128 CloogDomain *cloog_domain_simple_convex(CloogDomain *domain)
130 struct isl_basic_set *hull;
131 isl_set *set = isl_set_from_cloog_domain(domain);
133 if (cloog_domain_isconvex(domain))
134 return cloog_domain_copy(domain);
136 hull = isl_set_bounded_simple_hull(isl_set_copy(set));
137 return cloog_domain_from_isl_set(isl_set_from_basic_set(hull));
142 * cloog_domain_simplify function:
143 * Given two polyhedral domains (dom1) and (dom2),
144 * this function finds the largest domain set (or the smallest list
145 * of non-redundant constraints), that when intersected with polyhedral
146 * domain (dom2) equals (dom1)intersect(dom2). The output is a new CloogDomain
147 * structure with a polyhedral domain with the "redundant" constraints removed.
148 * NB: the second domain is required not to be a union.
150 CloogDomain *cloog_domain_simplify(CloogDomain *dom1, CloogDomain *dom2)
152 isl_set *set1 = isl_set_from_cloog_domain(dom1);
153 isl_set *set2 = isl_set_from_cloog_domain(dom2);
154 set1 = isl_set_gist(isl_set_copy(set1), isl_set_copy(set2));
155 return cloog_domain_from_isl_set(set1);
160 * cloog_domain_union function:
161 * This function returns a new polyhedral domain which is the union of
162 * two polyhedral domains (dom1) U (dom2).
163 * Frees dom1 and dom2;
165 CloogDomain *cloog_domain_union(CloogDomain *dom1, CloogDomain *dom2)
167 isl_set *set1 = isl_set_from_cloog_domain(dom1);
168 isl_set *set2 = isl_set_from_cloog_domain(dom2);
169 set1 = isl_set_union(set1, set2);
170 return cloog_domain_from_isl_set(set1);
176 * cloog_domain_intersection function:
177 * This function returns a new polyhedral domain which is the intersection of
178 * two polyhedral domains (dom1) \cap (dom2).
180 CloogDomain *cloog_domain_intersection(CloogDomain *dom1, CloogDomain *dom2)
182 isl_set *set1 = isl_set_from_cloog_domain(dom1);
183 isl_set *set2 = isl_set_from_cloog_domain(dom2);
184 set1 = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
185 return cloog_domain_from_isl_set(set1);
190 * cloog_domain_difference function:
191 * Returns the set difference domain \ minus.
193 CloogDomain *cloog_domain_difference(CloogDomain *domain, CloogDomain *minus)
195 isl_set *set1 = isl_set_from_cloog_domain(domain);
196 isl_set *set2 = isl_set_from_cloog_domain(minus);
197 set1 = isl_set_subtract(isl_set_copy(set1), isl_set_copy(set2));
198 return cloog_domain_from_isl_set(set1);
203 * cloog_domain_sort function:
204 * This function topologically sorts (nb_doms) domains. Here (doms) is an
205 * array of pointers to CloogDomains, (nb_doms) is the number of domains,
206 * (level) is the level to consider for partial ordering (nb_par) is the
207 * parameter space dimension, (permut) if not NULL, is an array of (nb_doms)
208 * integers that contains a permutation specification after call in order to
209 * apply the topological sorting.
211 void cloog_domain_sort(CloogDomain **doms, unsigned nb_doms, unsigned level,
212 int *permut)
214 int i, j, k, cmp;
215 struct isl_ctx *ctx;
216 unsigned char **follows;
217 isl_set *set_i, *set_j;
218 isl_basic_set *bset_i, *bset_j;
220 if (!nb_doms)
221 return;
222 set_i = isl_set_from_cloog_domain(doms[0]);
223 ctx = isl_set_get_ctx(set_i);
224 for (i = 0; i < nb_doms; i++) {
225 set_i = isl_set_from_cloog_domain(doms[i]);
226 assert(isl_set_n_basic_set(set_i) == 1);
229 follows = isl_alloc_array(ctx, unsigned char *, nb_doms);
230 assert(follows);
231 for (i = 0; i < nb_doms; ++i) {
232 follows[i] = isl_alloc_array(ctx, unsigned char, nb_doms);
233 assert(follows[i]);
234 for (j = 0; j < nb_doms; ++j)
235 follows[i][j] = 0;
238 for (i = 1; i < nb_doms; ++i) {
239 for (j = 0; j < i; ++j) {
240 if (follows[i][j] || follows[j][i])
241 continue;
242 set_i = isl_set_from_cloog_domain(doms[i]);
243 set_j = isl_set_from_cloog_domain(doms[j]);
244 bset_i = isl_set_copy_basic_set(set_i);
245 bset_j = isl_set_copy_basic_set(set_j);
246 cmp = isl_basic_set_compare_at(bset_i, bset_j, level-1);
247 isl_basic_set_free(bset_i);
248 isl_basic_set_free(bset_j);
249 if (!cmp)
250 continue;
251 if (cmp > 0) {
252 follows[i][j] = 1;
253 for (k = 0; k < i; ++k)
254 follows[i][k] |= follows[j][k];
255 } else {
256 follows[j][i] = 1;
257 for (k = 0; k < i; ++k)
258 follows[k][i] |= follows[k][j];
263 for (i = 0, j = 0; i < nb_doms; j = (j + 1) % nb_doms) {
264 for (k = 0; k < nb_doms; ++k)
265 if (follows[j][k])
266 break;
267 if (k < nb_doms)
268 continue;
269 for (k = 0; k < nb_doms; ++k)
270 follows[k][j] = 0;
271 follows[j][j] = 1;
272 permut[i] = 1 + j;
273 ++i;
276 for (i = 0; i < nb_doms; ++i)
277 free(follows[i]);
278 free(follows);
283 * Check whether there is or may be any value of dom1 at the given level
284 * that is greater than or equal to a value of dom2 at the same level.
286 * Return
287 * 1 is there is or may be a greater-than pair.
288 * 0 if there is no greater-than pair, but there may be an equal-to pair
289 * -1 if there is definitely no such pair
291 int cloog_domain_follows(CloogDomain *dom1, CloogDomain *dom2, unsigned level)
293 isl_set *set1 = isl_set_from_cloog_domain(dom1);
294 isl_set *set2 = isl_set_from_cloog_domain(dom2);
295 int follows;
297 follows = isl_set_follows_at(set1, set2, level - 1);
298 assert(follows >= -1);
300 return follows;
305 * cloog_domain_empty function:
306 * Returns an empty domain of the same dimensions as template.
308 CloogDomain *cloog_domain_empty(CloogDomain *template)
310 isl_set *set = isl_set_from_cloog_domain(template);
311 return cloog_domain_from_isl_set(isl_set_empty_like(set));
316 * Return 1 if the specified dimension has both an upper and a lower bound.
318 int cloog_domain_is_bounded(CloogDomain *dom, unsigned level)
320 isl_set *set = isl_set_from_cloog_domain(dom);
321 return isl_set_dim_is_bounded(set, isl_dim_set, level - 1);
325 /******************************************************************************
326 * Structure display function *
327 ******************************************************************************/
331 * cloog_domain_print_structure :
332 * this function is a more human-friendly way to display the CloogDomain data
333 * structure, it only shows the constraint system and includes an indentation
334 * level (level) in order to work with others print_structure functions.
336 void cloog_domain_print_structure(FILE *file, CloogDomain *domain, int level,
337 const char *name)
339 int i ;
340 isl_set *set = isl_set_from_cloog_domain(domain);
342 /* Go to the right level. */
343 for (i = 0; i < level; i++)
344 fprintf(file, "|\t");
346 if (!set) {
347 fprintf(file, "+-- Null CloogDomain\n");
348 return;
350 fprintf(file, "+-- %s\n", name);
351 for (i = 0; i < level+1; ++i)
352 fprintf(file, "|\t");
354 isl_set_print(set, file, 0, ISL_FORMAT_ISL);
356 fprintf(file, "\n");
360 /******************************************************************************
361 * Memory deallocation function *
362 ******************************************************************************/
365 void cloog_domain_list_free(CloogDomainList *list)
367 CloogDomainList *next;
369 for ( ; list; list = next) {
370 next = list->next;
371 cloog_domain_free(list->domain);
372 free(list);
378 * cloog_scattering_list_free function:
379 * This function frees the allocated memory for a CloogScatteringList structure.
381 void cloog_scattering_list_free(CloogScatteringList *list)
383 while (list != NULL) {
384 CloogScatteringList *temp = list->next;
385 isl_map *map = isl_map_from_cloog_scattering(list->scatt);
386 isl_map_free(map);
387 free(list);
388 list = temp;
393 /******************************************************************************
394 * Reading function *
395 ******************************************************************************/
399 * cloog_domain_read_context function:
400 * Read parameter domain.
402 CloogDomain *cloog_domain_read_context(CloogState *state, FILE *input)
404 struct isl_ctx *ctx = state->backend->ctx;
405 isl_set *set;
407 set = isl_set_read_from_file(ctx, input);
408 set = isl_set_move_dims(set, isl_dim_param, 0,
409 isl_dim_set, 0, isl_set_dim(set, isl_dim_set));
411 return cloog_domain_from_isl_set(set);
416 * cloog_domain_from_context
417 * Reinterpret context by turning parameters into variables.
419 CloogDomain *cloog_domain_from_context(CloogDomain *context)
421 isl_set *set = isl_set_from_cloog_domain(context);
423 set = isl_set_move_dims(set, isl_dim_set, 0,
424 isl_dim_param, 0, isl_set_dim(set, isl_dim_param));
426 return cloog_domain_from_isl_set(set);
431 * cloog_domain_union_read function:
432 * This function reads a union of polyhedra into a file (input) and
433 * returns a pointer to a CloogDomain containing the read information.
435 CloogDomain *cloog_domain_union_read(CloogState *state,
436 FILE *input, int nb_parameters)
438 struct isl_ctx *ctx = state->backend->ctx;
439 struct isl_set *set;
441 set = isl_set_read_from_file(ctx, input);
442 if (isl_set_dim(set, isl_dim_param) != nb_parameters) {
443 int dim = isl_set_dim(set, isl_dim_set);
444 set = isl_set_move_dims(set, isl_dim_param, 0,
445 isl_dim_set, dim - nb_parameters, nb_parameters);
447 return cloog_domain_from_isl_set(set);
452 * cloog_domain_read_scattering function:
453 * This function reads in a scattering function from the file input.
455 * We try to read the scattering relation as a map, but if it is
456 * specified in the original PolyLib format, then isl_map_read_from_file
457 * will treat the input as a set return a map with zero input dimensions.
458 * In this case, we need to decompose the set into a map from
459 * scattering dimensions to domain dimensions and then invert the
460 * resulting map.
462 CloogScattering *cloog_domain_read_scattering(CloogDomain *domain, FILE *input)
464 isl_set *set = isl_set_from_cloog_domain(domain);
465 isl_ctx *ctx = isl_set_get_ctx(set);
466 struct isl_map *scat;
467 unsigned nparam;
468 unsigned dim;
469 unsigned n_scat;
471 dim = isl_set_dim(set, isl_dim_set);
472 nparam = isl_set_dim(set, isl_dim_param);
473 scat = isl_map_read_from_file(ctx, input);
474 if (isl_map_dim(scat, isl_dim_param) != nparam) {
475 int n_out = isl_map_dim(scat, isl_dim_out);
476 scat = isl_map_move_dims(scat, isl_dim_param, 0,
477 isl_dim_out, n_out - nparam, nparam);
479 if (isl_map_dim(scat, isl_dim_in) != dim) {
480 n_scat = isl_map_dim(scat, isl_dim_out) - dim;
481 scat = isl_map_move_dims(scat, isl_dim_in, 0,
482 isl_dim_out, n_scat, dim);
484 return cloog_scattering_from_isl_map(scat);
487 /******************************************************************************
488 * CloogMatrix Reading function *
489 ******************************************************************************/
492 * isl_constraint_read_from_matrix:
493 * Convert a single line of a matrix to a isl_constraint.
494 * Returns a pointer to the constraint if successful; NULL otherwise.
496 static struct isl_constraint *isl_constraint_read_from_matrix(
497 struct isl_space *dim, cloog_int_t *row)
499 struct isl_constraint *constraint;
500 int j;
501 int nvariables = isl_space_dim(dim, isl_dim_set);
502 int nparam = isl_space_dim(dim, isl_dim_param);
503 isl_local_space *ls = isl_local_space_from_space(dim);
505 if (cloog_int_is_zero(row[0]))
506 constraint = isl_equality_alloc(ls);
507 else
508 constraint = isl_inequality_alloc(ls);
510 for (j = 0; j < nvariables; ++j)
511 isl_constraint_set_coefficient(constraint, isl_dim_out, j,
512 row[1 + j]);
514 for (j = 0; j < nparam; ++j)
515 isl_constraint_set_coefficient(constraint, isl_dim_param, j,
516 row[1 + nvariables + j]);
518 isl_constraint_set_constant(constraint, row[1 + nvariables + nparam]);
520 return constraint;
524 * isl_basic_set_read_from_matrix:
525 * Convert matrix to basic_set. The matrix contains nparam parameter columns.
526 * Returns a pointer to the basic_set if successful; NULL otherwise.
528 static struct isl_basic_set *isl_basic_set_read_from_matrix(struct isl_ctx *ctx,
529 CloogMatrix* matrix, int nparam)
531 struct isl_space *dim;
532 struct isl_basic_set *bset;
533 int i;
534 unsigned nrows, ncolumns;
536 nrows = matrix->NbRows;
537 ncolumns = matrix->NbColumns;
538 int nvariables = ncolumns - 2 - nparam;
540 dim = isl_space_set_alloc(ctx, nparam, nvariables);
542 bset = isl_basic_set_universe(isl_space_copy(dim));
544 for (i = 0; i < nrows; ++i) {
545 cloog_int_t *row = matrix->p[i];
546 struct isl_constraint *constraint =
547 isl_constraint_read_from_matrix(isl_space_copy(dim), row);
548 bset = isl_basic_set_add_constraint(bset, constraint);
551 isl_space_free(dim);
553 return bset;
557 * cloog_domain_from_cloog_matrix:
558 * Create a CloogDomain containing the constraints described in matrix.
559 * nparam is the number of parameters contained in the domain.
560 * Returns a pointer to the CloogDomain if successful; NULL otherwise.
562 CloogDomain *cloog_domain_from_cloog_matrix(CloogState *state,
563 CloogMatrix *matrix, int nparam)
565 struct isl_ctx *ctx = state->backend->ctx;
566 struct isl_basic_set *bset;
568 bset = isl_basic_set_read_from_matrix(ctx, matrix, nparam);
570 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
574 * cloog_scattering_from_cloog_matrix:
575 * Create a CloogScattering containing the constraints described in matrix.
576 * nparam is the number of parameters contained in the domain.
577 * Returns a pointer to the CloogScattering if successful; NULL otherwise.
579 CloogScattering *cloog_scattering_from_cloog_matrix(CloogState *state,
580 CloogMatrix *matrix, int nb_scat, int nb_par)
582 struct isl_ctx *ctx = state->backend->ctx;
583 struct isl_basic_set *bset;
584 struct isl_basic_map *scat;
585 struct isl_space *dims;
586 unsigned dim;
588 bset = isl_basic_set_read_from_matrix(ctx, matrix, nb_par);
589 dim = isl_basic_set_n_dim(bset) - nb_scat;
590 dims = isl_space_alloc(ctx, nb_par, nb_scat, dim);
592 scat = isl_basic_map_from_basic_set(bset, dims);
593 scat = isl_basic_map_reverse(scat);
594 return cloog_scattering_from_isl_map(isl_map_from_basic_map(scat));
598 /******************************************************************************
599 * Processing functions *
600 ******************************************************************************/
603 #ifdef OSL_SUPPORT
605 * Converts an openscop relation to a CLooG domain.
606 * \param[in,out] state CLooG state.
607 * \param[in] relation OpenScop relation to convert.
608 * \return A new CloogDomain corresponding to the input OpenScop relation.
610 CloogDomain *cloog_domain_from_osl_relation(CloogState *state,
611 osl_relation_p relation) {
612 char *str;
613 struct isl_ctx *ctx = state->backend->ctx;
614 isl_set *set;
615 CloogDomain *domain = NULL;
617 if (relation != NULL) {
618 if (relation->precision != OSL_PRECISION_MP)
619 cloog_die("Non-GMP precision is not supported yet.\n");
621 str = osl_relation_spprint_polylib(relation, NULL);
622 set = isl_set_read_from_str(ctx, str);
623 free(str);
625 domain = cloog_domain_from_isl_set(set);
628 return domain;
633 * Converts an openscop scattering relation to a CLooG scattering.
634 * \param[in,out] state CLooG state.
635 * \param[in] relation OpenScop relation to convert.
636 * \return A new CloogScattering corresponding to the input OpenScop relation.
638 CloogScattering *cloog_scattering_from_osl_relation(CloogState *state,
639 osl_relation_p relation) {
640 char *str;
641 struct isl_ctx *ctx = state->backend->ctx;
642 isl_map *map;
643 CloogScattering *scattering = NULL;
645 if (relation != NULL) {
646 if (relation->precision != OSL_PRECISION_MP)
647 cloog_die("Non-GMP precision is not supported yet.\n");
649 if (relation->type != OSL_TYPE_SCATTERING)
650 cloog_die("Cannot convert a non-scattering relation to a scattering.\n");
652 str = osl_relation_spprint_polylib(relation, NULL);
653 map = isl_map_read_from_str(ctx, str);
654 free(str);
656 scattering = cloog_scattering_from_isl_map(map);
659 return scattering;
661 #endif
664 * cloog_domain_isempty function:
666 int cloog_domain_isempty(CloogDomain *domain)
668 isl_set *set = isl_set_from_cloog_domain(domain);
669 return isl_set_is_empty(set);
674 * cloog_domain_universe function:
675 * This function returns the complete dim-dimensional space.
677 CloogDomain *cloog_domain_universe(CloogState *state, unsigned dim)
679 struct isl_space *dims;
680 struct isl_basic_set *bset;
682 dims = isl_space_set_alloc(state->backend->ctx, 0, dim);
683 bset = isl_basic_set_universe(dims);
684 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
689 * cloog_domain_project function:
690 * This function returns the projection of
691 * (domain) on the (level) first dimensions (i.e. outer loops).
693 CloogDomain *cloog_domain_project(CloogDomain *domain, int level)
695 isl_set *set = isl_set_from_cloog_domain(domain);
696 set = isl_set_remove_dims(isl_set_copy(set), isl_dim_set,
697 level, isl_set_n_dim(set) - level);
698 set = isl_set_compute_divs(set);
699 if (level > 0)
700 set = isl_set_remove_divs_involving_dims(set,
701 isl_dim_set, level - 1, 1);
702 return cloog_domain_from_isl_set(set);
707 * cloog_domain_extend function:
708 * This function returns the (domain) given as input with (dim)
709 * dimensions and (nb_par) parameters.
710 * This function does not free (domain), and returns a new CloogDomain.
712 CloogDomain *cloog_domain_extend(CloogDomain *domain, int dim)
714 isl_set *set = isl_set_from_cloog_domain(domain);
715 int n = isl_set_dim(set, isl_dim_set);
716 set = isl_set_add_dims(isl_set_copy(set), isl_dim_set, dim - n);
717 return cloog_domain_from_isl_set(set);
722 * cloog_domain_never_integral function:
723 * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0.
724 * There is no need to check for such constraints explicitly for the isl
725 * backend.
727 int cloog_domain_never_integral(CloogDomain * domain)
729 isl_set *set = isl_set_from_cloog_domain(domain);
730 return isl_set_is_empty(set);
735 * Check whether the loop at "level" is executed at most once.
736 * We construct a map that maps all remaining variables to this iterator
737 * and check whether this map is single valued.
739 * Alternatively, we could have mapped the domain through a mapping
740 * [p] -> { [..., i] -> [..., i'] : i' > i }
741 * and then taken the intersection of the original domain and the transformed
742 * domain. If this intersection is empty, then the corresponding
743 * loop is executed at most once.
745 int cloog_domain_is_otl(CloogDomain *domain, int level)
747 int otl;
748 isl_set *set = isl_set_from_cloog_domain(domain);
749 isl_map *map;
751 map = isl_map_from_domain(isl_set_copy(set));
752 map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_in, level - 1, 1);
753 otl = isl_map_is_single_valued(map);
754 isl_map_free(map);
756 return otl;
761 * cloog_domain_stride function:
762 * This function finds the stride imposed to unknown with the column number
763 * 'strided_level' in order to be integral. For instance, if we have a
764 * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral
765 * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to
766 * the unknown i. The function returns the imposed stride in a parameter field.
767 * - domain is the set of constraint we have to consider,
768 * - strided_level is the column number of the unknown for which a stride have
769 * to be found,
770 * - looking_level is the column number of the unknown that impose a stride to
771 * the first unknown.
772 * - stride is the stride that is returned back as a function parameter.
773 * - offset is the value of the constant c if the condition is of the shape
774 * (i + c)%s = 0, s being the stride.
776 void cloog_domain_stride(CloogDomain *domain, int strided_level,
777 cloog_int_t *stride, cloog_int_t *offset)
779 isl_set *set = isl_set_from_cloog_domain(domain);
780 isl_set_dim_residue_class(set, strided_level - 1, stride, offset);
781 if (!isl_int_is_zero(*offset))
782 isl_int_sub(*offset, *stride, *offset);
783 return;
787 struct cloog_can_stride {
788 int level;
789 int can_stride;
792 static int constraint_can_stride(__isl_take isl_constraint *c, void *user)
794 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
795 int i;
796 isl_int v;
797 unsigned n_div;
799 if (isl_constraint_is_equality(c)) {
800 isl_constraint_free(c);
801 return 0;
804 isl_int_init(v);
805 isl_constraint_get_coefficient(c, isl_dim_set, ccs->level - 1, &v);
806 if (isl_int_is_pos(v)) {
807 n_div = isl_constraint_dim(c, isl_dim_div);
808 for (i = 0; i < n_div; ++i) {
809 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
810 if (!isl_int_is_zero(v))
811 break;
813 if (i < n_div)
814 ccs->can_stride = 0;
816 isl_int_clear(v);
817 isl_constraint_free(c);
819 return 0;
822 static int basic_set_can_stride(__isl_take isl_basic_set *bset, void *user)
824 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
825 int r;
827 r = isl_basic_set_foreach_constraint(bset, constraint_can_stride, ccs);
828 isl_basic_set_free(bset);
829 return r;
834 * Return 1 if CLooG is allowed to perform stride detection on level "level"
835 * and 0 otherwise.
836 * Currently, stride detection is only allowed when none of the lower
837 * bound constraints involve any existentially quantified variables.
838 * The reason is that the current isl interface does not make it
839 * easy to construct an integer division that depends on other integer
840 * divisions.
841 * By not allowing existentially quantified variables in the constraints,
842 * we can ignore them in cloog_domain_stride_lower_bound.
844 int cloog_domain_can_stride(CloogDomain *domain, int level)
846 struct cloog_can_stride ccs = { level, 1 };
847 isl_set *set = isl_set_from_cloog_domain(domain);
848 int r;
849 r = isl_set_foreach_basic_set(set, basic_set_can_stride, &ccs);
850 assert(r == 0);
851 return ccs.can_stride;
855 struct cloog_stride_lower {
856 int level;
857 CloogStride *stride;
858 isl_set *set;
859 isl_basic_set *bounds;
862 /* If the given constraint is a lower bound on csl->level, then add
863 * a lower bound to csl->bounds that makes sure that the remainder
864 * of the smallest value on division by csl->stride is equal to csl->offset.
866 * In particular, the given lower bound is of the form
868 * a i + f >= 0
870 * where f may depend on the parameters and other iterators.
871 * The stride is s and the offset is d.
872 * The lower bound -f/a may not satisfy the above condition. In fact,
873 * it may not even be integral. We want to round this value of i up
874 * to the nearest value that satisfies the condition and add the corresponding
875 * lower bound constraint. This nearest value is obtained by rounding
876 * i - d up to the nearest multiple of s.
877 * That is, we first subtract d
879 * i' = -f/a - d
881 * then we round up to the nearest multiple of s
883 * i'' = s * ceil(i'/s)
885 * and finally, we add d again
887 * i''' = i'' + d
889 * and impose the constraint i >= i'''.
891 * We find
893 * i'' = s * ceil((-f - a * d)/(a * s)) = - s * floor((f + a * d)/(a * s))
895 * i >= - s * floor((f + a * d)/(a * s)) + d
897 * or
898 * i + s * floor((f + a * d)/(a * s)) - d >= 0
900 static int constraint_stride_lower(__isl_take isl_constraint *c, void *user)
902 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
903 isl_int v;
904 isl_constraint *bound;
905 isl_aff *b;
907 if (isl_constraint_is_equality(c)) {
908 isl_constraint_free(c);
909 return 0;
912 isl_int_init(v);
913 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
914 if (!isl_int_is_pos(v)) {
915 isl_int_clear(v);
916 isl_constraint_free(c);
918 return 0;
921 b = isl_constraint_get_bound(c, isl_dim_set, csl->level - 1);
923 b = isl_aff_neg(b);
924 b = isl_aff_add_constant(b, csl->stride->offset);
925 b = isl_aff_scale_down(b, csl->stride->stride);
926 b = isl_aff_floor(b);
927 b = isl_aff_scale(b, csl->stride->stride);
928 isl_int_neg(v, csl->stride->offset);
929 b = isl_aff_add_constant(b, v);
930 b = isl_aff_add_coefficient_si(b, isl_dim_in, csl->level - 1, 1);
932 bound = isl_inequality_from_aff(b);
934 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
936 isl_int_clear(v);
937 isl_constraint_free(c);
939 return 0;
942 /* This functions performs essentially the same operation as
943 * constraint_stride_lower, the only difference being that the offset d
944 * is not a constant, but an affine expression in terms of the parameters
945 * and earlier variables. In particular the affine expression is equal
946 * to the coefficients of stride->constraint multiplied by stride->factor.
947 * As in constraint_stride_lower, we add an extra bound
949 * i + s * floor((f + a * d)/(a * s)) - d >= 0
951 * for each lower bound
953 * a i + f >= 0
955 * where d is not the aforementioned affine expression.
957 static int constraint_stride_lower_c(__isl_take isl_constraint *c, void *user)
959 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
960 isl_int v;
961 isl_constraint *bound;
962 isl_constraint *csl_c;
963 isl_aff *d, *b;
965 if (isl_constraint_is_equality(c)) {
966 isl_constraint_free(c);
967 return 0;
970 isl_int_init(v);
971 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
972 if (!isl_int_is_pos(v)) {
973 isl_int_clear(v);
974 isl_constraint_free(c);
976 return 0;
979 csl_c = cloog_constraint_to_isl(csl->stride->constraint);
981 d = isl_constraint_get_aff(csl_c);
982 d = isl_aff_drop_dims(d, isl_dim_div, 0, isl_aff_dim(d, isl_dim_div));
983 d = isl_aff_set_coefficient_si(d, isl_dim_in, csl->level - 1, 0);
984 d = isl_aff_scale(d, csl->stride->factor);
986 b = isl_constraint_get_bound(c, isl_dim_set, csl->level - 1);
988 b = isl_aff_neg(b);
989 b = isl_aff_add(b, isl_aff_copy(d));
990 b = isl_aff_scale_down(b, csl->stride->stride);
991 b = isl_aff_floor(b);
992 b = isl_aff_scale(b, csl->stride->stride);
993 b = isl_aff_sub(b, d);
994 b = isl_aff_add_coefficient_si(b, isl_dim_in, csl->level - 1, 1);
996 bound = isl_inequality_from_aff(b);
998 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
1000 isl_int_clear(v);
1001 isl_constraint_free(c);
1003 return 0;
1006 static int basic_set_stride_lower(__isl_take isl_basic_set *bset, void *user)
1008 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
1009 int r;
1011 csl->bounds = isl_basic_set_universe_like(bset);
1012 if (csl->stride->constraint)
1013 r = isl_basic_set_foreach_constraint(bset,
1014 &constraint_stride_lower_c, csl);
1015 else
1016 r = isl_basic_set_foreach_constraint(bset,
1017 &constraint_stride_lower, csl);
1018 bset = isl_basic_set_intersect(bset, csl->bounds);
1019 csl->set = isl_set_union(csl->set, isl_set_from_basic_set(bset));
1021 return r;
1025 * Update the lower bounds at level "level" to the given stride information.
1026 * That is, make sure that the remainder on division by "stride"
1027 * is equal to "offset".
1029 CloogDomain *cloog_domain_stride_lower_bound(CloogDomain *domain, int level,
1030 CloogStride *stride)
1032 struct cloog_stride_lower csl;
1033 isl_set *set = isl_set_from_cloog_domain(domain);
1034 int r;
1036 csl.stride = stride;
1037 csl.level = level;
1038 csl.set = isl_set_empty_like(set);
1040 r = isl_set_foreach_basic_set(set, basic_set_stride_lower, &csl);
1041 assert(r == 0);
1043 cloog_domain_free(domain);
1044 return cloog_domain_from_isl_set(csl.set);
1048 /* Add stride constraint, if any, to domain.
1050 CloogDomain *cloog_domain_add_stride_constraint(CloogDomain *domain,
1051 CloogStride *stride)
1053 isl_constraint *c;
1054 isl_set *set;
1056 if (!stride || !stride->constraint)
1057 return domain;
1059 set = isl_set_from_cloog_domain(domain);
1060 c = isl_constraint_copy(cloog_constraint_to_isl(stride->constraint));
1062 set = isl_set_add_constraint(set, c);
1064 return cloog_domain_from_isl_set(set);
1069 * cloog_domain_lazy_equal function:
1070 * This function returns 1 if the domains given as input are the same, 0 if it
1071 * is unable to decide.
1073 int cloog_domain_lazy_equal(CloogDomain *d1, CloogDomain *d2)
1075 isl_set *set1 = isl_set_from_cloog_domain(d1);
1076 isl_set *set2 = isl_set_from_cloog_domain(d2);
1077 return isl_set_fast_is_equal(set1, set2);
1080 struct cloog_bound_split {
1081 isl_set *set;
1082 int level;
1083 int lower;
1084 int upper;
1087 static int constraint_bound_split(__isl_take isl_constraint *c, void *user)
1089 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1090 isl_int v;
1091 int i;
1092 int handle = 0;
1094 isl_int_init(v);
1095 isl_constraint_get_coefficient(c, isl_dim_set, cbs->level - 1, &v);
1096 if (!cbs->lower && isl_int_is_pos(v))
1097 cbs->lower = handle = 1;
1098 else if (!cbs->upper && isl_int_is_neg(v))
1099 cbs->upper = handle = 1;
1100 if (handle) {
1101 for (i = 0; i < isl_set_dim(cbs->set, isl_dim_param); ++i) {
1102 isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
1103 if (isl_int_is_zero(v))
1104 continue;
1105 cbs->set = isl_set_split_dims(cbs->set,
1106 isl_dim_param, i, 1);
1109 isl_int_clear(v);
1110 isl_constraint_free(c);
1112 return (cbs->lower && cbs->upper) ? -1 : 0;
1115 static int basic_set_bound_split(__isl_take isl_basic_set *bset, void *user)
1117 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1118 int r;
1120 cbs->lower = 0;
1121 cbs->upper = 0;
1122 r = isl_basic_set_foreach_constraint(bset, constraint_bound_split, cbs);
1123 isl_basic_set_free(bset);
1124 return ((!cbs->lower || !cbs->upper) && r < 0) ? -1 : 0;
1128 * Return a union of sets S_i such that the convex hull of "dom",
1129 * when intersected with one the sets S_i, will have an upper and
1130 * lower bound for the dimension at "level" (provided "dom" itself
1131 * has such bounds for the dimensions).
1133 * We currently take a very simple approach. For each of the basic
1134 * sets in "dom" we pick a lower and an upper bound and split the
1135 * range of any parameter involved in these two bounds in a
1136 * nonnegative and a negative part. This ensures that the symbolic
1137 * constant in these two constraints are themselves bounded and
1138 * so there will be at least one upper and one lower bound
1139 * in the convex hull.
1141 CloogDomain *cloog_domain_bound_splitter(CloogDomain *dom, int level)
1143 struct cloog_bound_split cbs;
1144 isl_set *set = isl_set_from_cloog_domain(dom);
1145 int r;
1146 cbs.level = level;
1147 cbs.set = isl_set_universe_like(set);
1148 r = isl_set_foreach_basic_set(set, basic_set_bound_split, &cbs);
1149 assert(r == 0);
1150 return cloog_domain_from_isl_set(cbs.set);
1154 /* Check whether the union of scattering functions over all domains
1155 * is obviously injective.
1157 static int injective_scattering(CloogScatteringList *list)
1159 isl_map *map;
1160 isl_union_map *umap;
1161 int injective;
1162 int i = 0;
1163 char name[30];
1165 if (!list)
1166 return 1;
1168 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1169 snprintf(name, sizeof(name), "S%d", i);
1170 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1171 umap = isl_union_map_from_map(map);
1173 for (list = list->next, ++i; list; list = list->next, ++i) {
1174 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1175 snprintf(name, sizeof(name), "S%d", i);
1176 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1177 umap = isl_union_map_add_map(umap, map);
1180 injective = isl_union_map_plain_is_injective(umap);
1182 isl_union_map_free(umap);
1184 return injective;
1189 * cloog_scattering_lazy_block function:
1190 * This function returns 1 if the two scattering functions s1 and s2 given
1191 * as input are the same (except possibly for the final dimension, where we
1192 * allow a difference of 1), assuming that the domains on which this
1193 * scatterings are applied are the same.
1194 * In fact this function answers the question "can I
1195 * safely consider the two domains as only one with two statements (a block) ?".
1196 * A difference of 1 in the final dimension is only allowed if the
1197 * entire scattering function is injective.
1198 * - s1 and s2 are the two domains to check for blocking,
1199 * - scattering is the linked list of all domains,
1200 * - scattdims is the total number of scattering dimentions.
1202 int cloog_scattering_lazy_block(CloogScattering *s1, CloogScattering *s2,
1203 CloogScatteringList *scattering, int scattdims)
1205 int i;
1206 struct isl_space *dim;
1207 struct isl_map *rel;
1208 struct isl_set *delta;
1209 isl_map *map1 = isl_map_from_cloog_scattering(s1);
1210 isl_map *map2 = isl_map_from_cloog_scattering(s2);
1211 int fixed, block;
1212 isl_int cst;
1213 unsigned n_scat;
1215 n_scat = isl_map_dim(map1, isl_dim_out);
1216 if (n_scat != isl_map_dim(map2, isl_dim_out))
1217 return 0;
1219 dim = isl_map_get_space(map1);
1220 dim = isl_space_map_from_set(isl_space_domain(dim));
1221 rel = isl_map_identity(dim);
1222 rel = isl_map_apply_domain(rel, isl_map_copy(map1));
1223 rel = isl_map_apply_range(rel, isl_map_copy(map2));
1224 delta = isl_map_deltas(rel);
1225 isl_int_init(cst);
1226 for (i = 0; i < n_scat; ++i) {
1227 fixed = isl_set_fast_dim_is_fixed(delta, i, &cst);
1228 if (fixed != 1)
1229 break;
1230 if (isl_int_is_zero(cst))
1231 continue;
1232 if (i + 1 < n_scat)
1233 break;
1234 if (!isl_int_is_one(cst))
1235 break;
1236 if (!injective_scattering(scattering))
1237 break;
1239 block = i >= n_scat;
1240 isl_int_clear(cst);
1241 isl_set_free(delta);
1242 return block;
1247 * cloog_domain_lazy_disjoint function:
1248 * This function returns 1 if the domains given as input are disjoint, 0 if it
1249 * is unable to decide.
1251 int cloog_domain_lazy_disjoint(CloogDomain *d1, CloogDomain *d2)
1253 isl_set *set1 = isl_set_from_cloog_domain(d1);
1254 isl_set *set2 = isl_set_from_cloog_domain(d2);
1255 return isl_set_fast_is_disjoint(set1, set2);
1260 * cloog_scattering_list_lazy_same function:
1261 * This function returns 1 if two domains in the list are the same, 0 if it
1262 * is unable to decide.
1264 int cloog_scattering_list_lazy_same(CloogScatteringList *list)
1266 CloogScatteringList *one, *other;
1267 isl_map *one_map, *other_map;
1269 for (one = list; one; one = one->next) {
1270 one_map = isl_map_from_cloog_scattering(one->scatt);
1271 for (other = one->next; other; other = other->next) {
1272 other_map = isl_map_from_cloog_scattering(other->scatt);
1273 if (isl_map_fast_is_equal(one_map, other_map))
1274 return 1;
1277 return 0;
1280 int cloog_domain_dimension(CloogDomain * domain)
1282 isl_set *set = isl_set_from_cloog_domain(domain);
1283 return isl_set_dim(set, isl_dim_set);
1286 int cloog_domain_parameter_dimension(CloogDomain *domain)
1288 isl_set *set = isl_set_from_cloog_domain(domain);
1289 return isl_set_dim(set, isl_dim_param);
1292 int cloog_scattering_dimension(CloogScattering *scatt, CloogDomain *domain)
1294 isl_map *map = isl_map_from_cloog_scattering(scatt);
1295 return isl_map_dim(map, isl_dim_out);
1298 int cloog_domain_isconvex(CloogDomain * domain)
1300 isl_set *set = isl_set_from_cloog_domain(domain);
1301 return isl_set_n_basic_set(set) <= 1;
1306 * cloog_domain_cut_first function:
1307 * This function splits off and returns the first convex set in the
1308 * union "domain". The remainder of the union is returned in rest.
1309 * The original "domain" itself is destroyed and may not be used
1310 * after a call to this function.
1312 CloogDomain *cloog_domain_cut_first(CloogDomain *domain, CloogDomain **rest)
1314 isl_set *set = isl_set_from_cloog_domain(domain);
1315 struct isl_basic_set *first;
1317 first = isl_set_copy_basic_set(set);
1318 set = isl_set_drop_basic_set(set, first);
1319 *rest = cloog_domain_from_isl_set(set);
1321 return cloog_domain_from_isl_set(isl_set_from_basic_set(first));
1326 * Given a union domain, try to find a simpler representation
1327 * using fewer sets in the union.
1328 * The original "domain" itself is destroyed and may not be used
1329 * after a call to this function.
1331 CloogDomain *cloog_domain_simplify_union(CloogDomain *domain)
1333 isl_set *set = isl_set_from_cloog_domain(domain);
1334 return cloog_domain_from_isl_set(isl_set_coalesce(set));
1339 * cloog_scattering_lazy_isscalar function:
1340 * this function returns 1 if the scattering dimension 'dimension' in the
1341 * scattering 'scatt' is constant.
1342 * If value is not NULL, then it is set to the constant value of dimension.
1344 int cloog_scattering_lazy_isscalar(CloogScattering *scatt, int dimension,
1345 cloog_int_t *value)
1347 isl_map *map = isl_map_from_cloog_scattering(scatt);
1348 return isl_map_fast_is_fixed(map, isl_dim_out, dimension, value);
1353 * cloog_domain_lazy_isconstant function:
1354 * this function returns 1 if the dimension 'dimension' in the
1355 * domain 'domain' is constant.
1356 * If value is not NULL, then it is set to the constant value of dimension.
1358 int cloog_domain_lazy_isconstant(CloogDomain *domain, int dimension,
1359 cloog_int_t *value)
1361 isl_set *set = isl_set_from_cloog_domain(domain);
1362 return isl_set_fast_dim_is_fixed(set, dimension, value);
1367 * cloog_scattering_erase_dimension function:
1368 * this function returns a CloogDomain structure builds from 'domain' where
1369 * we removed the dimension 'dimension' and every constraint involving this
1370 * dimension.
1372 CloogScattering *cloog_scattering_erase_dimension(CloogScattering *scattering,
1373 int dimension)
1375 isl_map *map = isl_map_from_cloog_scattering(scattering);
1376 map = isl_map_remove_dims(isl_map_copy(map), isl_dim_out, dimension, 1);
1377 return cloog_scattering_from_isl_map(map);
1381 * cloog_domain_cube:
1382 * Construct and return a dim-dimensional cube, with values ranging
1383 * between min and max in each dimension.
1385 CloogDomain *cloog_domain_cube(CloogState *state,
1386 int dim, cloog_int_t min, cloog_int_t max)
1388 int i;
1389 struct isl_basic_set *cube;
1390 struct isl_basic_set *interval;
1391 struct isl_basic_set_list *list;
1393 if (dim == 0)
1394 return cloog_domain_universe(state, dim);
1396 interval = isl_basic_set_interval(state->backend->ctx, min, max);
1397 list = isl_basic_set_list_alloc(state->backend->ctx, dim);
1398 for (i = 0; i < dim; ++i)
1399 list = isl_basic_set_list_add(list, isl_basic_set_copy(interval));
1400 isl_basic_set_free(interval);
1401 cube = isl_basic_set_list_product(list);
1402 return cloog_domain_from_isl_set(isl_set_from_basic_set(cube));
1407 * cloog_domain_scatter function:
1408 * This function add the scattering (scheduling) informations to a domain.
1410 CloogDomain *cloog_domain_scatter(CloogDomain *domain, CloogScattering *scatt)
1412 isl_set *set = isl_set_from_cloog_domain(domain);
1413 isl_map *map = isl_map_from_cloog_scattering(scatt);
1415 map = isl_map_reverse(isl_map_copy(map));
1416 map = isl_map_intersect_range(map, set);
1417 set = isl_set_flatten(isl_map_wrap(map));
1418 return cloog_domain_from_isl_set(set);
1421 static int add_domain_from_map(__isl_take isl_map *map, void *user)
1423 isl_space *dim;
1424 const char *name;
1425 CloogDomain *domain;
1426 CloogScattering *scat;
1427 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1429 dim = isl_map_get_space(map);
1430 name = isl_space_get_tuple_name(dim, isl_dim_in);
1431 domain = cloog_domain_from_isl_set(isl_map_domain(isl_map_copy(map)));
1432 scat = cloog_scattering_from_isl_map(map);
1433 *ud = cloog_union_domain_add_domain(*ud, name, domain, scat, NULL);
1434 isl_space_free(dim);
1436 return 0;
1440 * Construct a CloogUnionDomain from an isl_union_map representing
1441 * a global scattering function. The input is a mapping from different
1442 * spaces (different tuple names and possibly different dimensions)
1443 * to a common space. The iteration domains are set to the domains
1444 * in each space. The statement names are set to the names of the
1445 * spaces. The parameter names of the result are set to those of
1446 * the input, but the iterator and scattering dimension names are
1447 * left unspecified.
1449 CloogUnionDomain *cloog_union_domain_from_isl_union_map(
1450 __isl_take isl_union_map *umap)
1452 int i;
1453 int nparam;
1454 isl_space *dim;
1455 CloogUnionDomain *ud;
1457 dim = isl_union_map_get_space(umap);
1458 nparam = isl_space_dim(dim, isl_dim_param);
1460 ud = cloog_union_domain_alloc(nparam);
1462 for (i = 0; i < nparam; ++i) {
1463 const char *s = isl_space_get_dim_name(dim, isl_dim_param, i);
1464 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1466 isl_space_free(dim);
1468 if (isl_union_map_foreach_map(umap, &add_domain_from_map, &ud) < 0) {
1469 isl_union_map_free(umap);
1470 cloog_union_domain_free(ud);
1471 assert(0);
1474 isl_union_map_free(umap);
1476 return ud;
1479 static int count_same_name(__isl_keep isl_space *dim,
1480 enum isl_dim_type type, unsigned pos, const char *name)
1482 enum isl_dim_type t;
1483 unsigned p, s;
1484 int count = 0;
1485 int len = strlen(name);
1487 for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) {
1488 s = t == type ? pos : isl_space_dim(dim, t);
1489 for (p = 0; p < s; ++p) {
1490 const char *n = isl_space_get_dim_name(dim, t, p);
1491 if (n && !strncmp(n, name, len))
1492 count++;
1495 return count;
1498 static CloogUnionDomain *add_domain(__isl_take isl_set *set, CloogUnionDomain *ud)
1500 int i, nvar;
1501 isl_ctx *ctx;
1502 isl_space *dim;
1503 char buffer[20];
1504 const char *name;
1505 CloogDomain *domain;
1507 ctx = isl_set_get_ctx(set);
1508 dim = isl_set_get_space(set);
1509 name = isl_space_get_tuple_name(dim, isl_dim_set);
1510 set = isl_set_flatten(set);
1511 set = isl_set_set_tuple_name(set, NULL);
1512 domain = cloog_domain_from_isl_set(set);
1513 ud = cloog_union_domain_add_domain(ud, name, domain, NULL, NULL);
1515 nvar = isl_space_dim(dim, isl_dim_set);
1516 for (i = 0; i < nvar; ++i) {
1517 char *long_name = NULL;
1518 int n;
1520 name = isl_space_get_dim_name(dim, isl_dim_set, i);
1521 if (!name) {
1522 snprintf(buffer, sizeof(buffer), "i%d", i);
1523 name = buffer;
1525 n = count_same_name(dim, isl_dim_set, i, name);
1526 if (n) {
1527 int size = strlen(name) + 10;
1528 long_name = isl_alloc_array(ctx, char, size);
1529 if (!long_name)
1530 cloog_die("memory overflow.\n");
1531 snprintf(long_name, size, "%s_%d", name, n);
1532 name = long_name;
1534 ud = cloog_union_domain_set_name(ud, CLOOG_ITER, i, name);
1535 free(long_name);
1537 isl_space_free(dim);
1539 return ud;
1543 * Construct a CloogUnionDomain from an isl_set.
1544 * The statement names are set to the names of the
1545 * spaces. The parameter and iterator names of the result are set to those of
1546 * the input, but the scattering dimension names are left unspecified.
1548 CloogUnionDomain *cloog_union_domain_from_isl_set(
1549 __isl_take isl_set *set)
1551 int i;
1552 int nparam;
1553 isl_space *dim;
1554 CloogUnionDomain *ud;
1556 dim = isl_set_get_space(set);
1557 nparam = isl_space_dim(dim, isl_dim_param);
1559 ud = cloog_union_domain_alloc(nparam);
1561 for (i = 0; i < nparam; ++i) {
1562 const char *s = isl_space_get_dim_name(dim, isl_dim_param, i);
1563 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1565 isl_space_free(dim);
1567 ud = add_domain(set, ud);
1569 return ud;
1572 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
1573 static void Euclid(cloog_int_t a, cloog_int_t b,
1574 cloog_int_t *x, cloog_int_t *y, cloog_int_t *g)
1576 cloog_int_t c, d, e, f, tmp;
1578 cloog_int_init(c);
1579 cloog_int_init(d);
1580 cloog_int_init(e);
1581 cloog_int_init(f);
1582 cloog_int_init(tmp);
1583 cloog_int_abs(c, a);
1584 cloog_int_abs(d, b);
1585 cloog_int_set_si(e, 1);
1586 cloog_int_set_si(f, 0);
1587 while (cloog_int_is_pos(d)) {
1588 cloog_int_tdiv_q(tmp, c, d);
1589 cloog_int_mul(tmp, tmp, f);
1590 cloog_int_sub(e, e, tmp);
1591 cloog_int_tdiv_q(tmp, c, d);
1592 cloog_int_mul(tmp, tmp, d);
1593 cloog_int_sub(c, c, tmp);
1594 cloog_int_swap(c, d);
1595 cloog_int_swap(e, f);
1597 cloog_int_set(*g, c);
1598 if (cloog_int_is_zero(a))
1599 cloog_int_set_si(*x, 0);
1600 else if (cloog_int_is_pos(a))
1601 cloog_int_set(*x, e);
1602 else cloog_int_neg(*x, e);
1603 if (cloog_int_is_zero(b))
1604 cloog_int_set_si(*y, 0);
1605 else {
1606 cloog_int_mul(tmp, a, *x);
1607 cloog_int_sub(tmp, c, tmp);
1608 cloog_int_divexact(*y, tmp, b);
1610 cloog_int_clear(c);
1611 cloog_int_clear(d);
1612 cloog_int_clear(e);
1613 cloog_int_clear(f);
1614 cloog_int_clear(tmp);
1617 /* Construct a CloogStride from the given constraint for the given level,
1618 * if possible.
1619 * We first compute the gcd of the coefficients of the existentially
1620 * quantified variables and then remove any common factors it has
1621 * with the coefficient at the given level.
1622 * The result is the value of the stride and if it is not one,
1623 * then it is possible to construct a CloogStride.
1624 * The constraint leading to the stride is stored in the CloogStride
1625 * as well a value (factor) such that the product of this value
1626 * and the coefficient at the given level is equal to -1 modulo the stride.
1628 static CloogStride *construct_stride(isl_constraint *c, int level)
1630 int i, n, sign;
1631 isl_int v, m, gcd, stride, factor;
1632 CloogStride *s;
1634 if (!c)
1635 return NULL;
1637 isl_int_init(v);
1638 isl_int_init(m);
1639 isl_int_init(gcd);
1640 isl_int_init(factor);
1641 isl_int_init(stride);
1643 isl_constraint_get_coefficient(c, isl_dim_set, level - 1, &v);
1644 sign = isl_int_sgn(v);
1645 isl_int_abs(m, v);
1647 isl_int_set_si(gcd, 0);
1648 n = isl_constraint_dim(c, isl_dim_div);
1649 for (i = 0; i < n; ++i) {
1650 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
1651 isl_int_gcd(gcd, gcd, v);
1654 isl_int_gcd(v, m, gcd);
1655 isl_int_divexact(stride, gcd, v);
1657 if (isl_int_is_zero(stride) || isl_int_is_one(stride))
1658 s = NULL;
1659 else {
1660 Euclid(m, stride, &factor, &v, &gcd);
1661 if (sign > 0)
1662 isl_int_neg(factor, factor);
1664 c = isl_constraint_copy(c);
1665 s = cloog_stride_alloc_from_constraint(stride,
1666 cloog_constraint_from_isl_constraint(c), factor);
1669 isl_int_clear(stride);
1670 isl_int_clear(factor);
1671 isl_int_clear(gcd);
1672 isl_int_clear(m);
1673 isl_int_clear(v);
1675 return s;
1678 struct cloog_isl_find_stride_data {
1679 int level;
1680 CloogStride *stride;
1683 /* Check if the given constraint can be used to derive
1684 * a stride on the iterator identified by data->level.
1685 * We first check that there are some existentially quantified variables
1686 * and that the coefficient at data->level is non-zero.
1687 * Then we call construct_stride for further checks and the actual
1688 * construction of the CloogStride.
1690 static int find_stride(__isl_take isl_constraint *c, void *user)
1692 struct cloog_isl_find_stride_data *data;
1693 int n;
1694 isl_int v;
1696 data = (struct cloog_isl_find_stride_data *)user;
1698 if (data->stride) {
1699 isl_constraint_free(c);
1700 return 0;
1703 n = isl_constraint_dim(c, isl_dim_div);
1704 if (n == 0) {
1705 isl_constraint_free(c);
1706 return 0;
1709 isl_int_init(v);
1711 isl_constraint_get_coefficient(c, isl_dim_set, data->level - 1, &v);
1712 if (!isl_int_is_zero(v))
1713 data->stride = construct_stride(c, data->level);
1715 isl_int_clear(v);
1717 isl_constraint_free(c);
1719 return 0;
1722 /* Check if the given list of domains has a common stride on the given level.
1723 * If so, return a pointer to a CloogStride object. If not, return NULL.
1725 * We project out all later variables, take the union and compute
1726 * the affine hull of the union. Then we check the (equality)
1727 * constraints in this affine hull for imposing a stride.
1729 CloogStride *cloog_domain_list_stride(CloogDomainList *list, int level)
1731 struct cloog_isl_find_stride_data data = { level, NULL };
1732 isl_set *set;
1733 isl_basic_set *aff;
1734 int first = level;
1735 int n;
1736 int r;
1738 set = isl_set_from_cloog_domain(list->domain);
1739 n = isl_set_dim(set, isl_dim_set) - first;
1740 set = isl_set_project_out(isl_set_copy(set), isl_dim_set, first, n);
1742 for (list = list->next; list; list = list->next) {
1743 isl_set *set_i = isl_set_from_cloog_domain(list->domain);
1744 n = isl_set_dim(set_i, isl_dim_set) - first;
1745 set_i = isl_set_project_out(isl_set_copy(set_i),
1746 isl_dim_set, first, n);
1747 set = isl_set_union(set, set_i);
1749 aff = isl_set_affine_hull(set);
1751 r = isl_basic_set_foreach_constraint(aff, &find_stride, &data);
1752 assert(r == 0);
1754 isl_basic_set_free(aff);
1756 return data.stride;
1759 struct cloog_can_unroll {
1760 int can_unroll;
1761 int level;
1762 isl_constraint *c;
1763 isl_set *set;
1764 isl_int *n;
1769 * Check if the given lower bound can be used for unrolling
1770 * and, if so, return the unrolling factor/trip count in *v.
1771 * If the lower bound involves any existentially quantified
1772 * variables, we currently punt.
1773 * Otherwise we compute the maximal value of (i - ceil(l) + 1),
1774 * with l the given lower bound and i the iterator identified by level.
1776 static int is_valid_unrolling_lower_bound(struct cloog_can_unroll *ccu,
1777 __isl_keep isl_constraint *c, isl_int *v)
1779 unsigned n_div;
1780 isl_aff *aff;
1781 enum isl_lp_result res;
1783 n_div = isl_constraint_dim(c, isl_dim_div);
1784 if (isl_constraint_involves_dims(c, isl_dim_div, 0, n_div))
1785 return 0;
1787 aff = isl_constraint_get_bound(c, isl_dim_set, ccu->level - 1);
1788 aff = isl_aff_ceil(aff);
1789 aff = isl_aff_neg(aff);
1790 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, ccu->level - 1, 1);
1791 res = isl_set_max(ccu->set, aff, v);
1792 isl_aff_free(aff);
1794 if (res == isl_lp_unbounded)
1795 return 0;
1797 assert(res == isl_lp_ok);
1799 cloog_int_add_ui(*v, *v, 1);
1801 return 1;
1805 /* Check if we can unroll based on the given constraint.
1806 * Only lower bounds can be used.
1807 * Record it if it turns out to be usable and if we haven't recorded
1808 * any other constraint already.
1810 static int constraint_can_unroll(__isl_take isl_constraint *c, void *user)
1812 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1813 isl_int v;
1814 isl_int count;
1816 isl_int_init(v);
1817 isl_int_init(count);
1818 isl_constraint_get_coefficient(c, isl_dim_set, ccu->level - 1, &v);
1819 if (isl_int_is_pos(v) &&
1820 is_valid_unrolling_lower_bound(ccu, c, &count) &&
1821 (!ccu->c || isl_int_lt(count, *ccu->n))) {
1822 isl_constraint_free(ccu->c);
1823 ccu->c = isl_constraint_copy(c);
1824 isl_int_set(*ccu->n, count);
1826 isl_int_clear(count);
1827 isl_int_clear(v);
1828 isl_constraint_free(c);
1830 return 0;
1834 /* Check if we can unroll the domain at the current level.
1835 * If the domain is a union, we cannot. Otherwise, we check the
1836 * constraints.
1838 static int basic_set_can_unroll(__isl_take isl_basic_set *bset, void *user)
1840 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1841 int r = 0;
1843 if (ccu->c || !ccu->can_unroll)
1844 ccu->can_unroll = 0;
1845 else {
1846 bset = isl_basic_set_remove_redundancies(bset);
1847 r = isl_basic_set_foreach_constraint(bset,
1848 &constraint_can_unroll, ccu);
1850 isl_basic_set_free(bset);
1851 return r;
1855 /* Check if we can unroll the given domain at the given level, and
1856 * if so, return the single lower bound in *lb and an upper bound
1857 * on the number of iterations in *n.
1858 * If we cannot unroll, return 0 and set *lb to NULL.
1860 * We can unroll, if we can identify a lower bound on level
1861 * such that the number of iterations is bounded by a constant.
1863 int cloog_domain_can_unroll(CloogDomain *domain, int level, cloog_int_t *n,
1864 CloogConstraint **lb)
1866 isl_set *set = isl_set_from_cloog_domain(domain);
1867 struct cloog_can_unroll ccu = { 1, level, NULL, set, n };
1868 int r;
1870 *lb = NULL;
1871 r = isl_set_foreach_basic_set(set, &basic_set_can_unroll, &ccu);
1872 assert(r == 0);
1873 if (!ccu.c)
1874 ccu.can_unroll = 0;
1875 if (!ccu.can_unroll) {
1876 isl_constraint_free(ccu.c);
1877 return 0;
1880 *lb = cloog_constraint_from_isl_constraint(ccu.c);
1882 return ccu.can_unroll;
1886 /* Fix the iterator i at the given level to l + o,
1887 * where l is prescribed by the constraint lb and o is equal to offset.
1888 * In particular, if lb is the constraint
1890 * a i >= f(j)
1892 * then l = ceil(f(j)/a).
1894 CloogDomain *cloog_domain_fixed_offset(CloogDomain *domain,
1895 int level, CloogConstraint *lb, cloog_int_t offset)
1897 isl_aff *aff;
1898 isl_set *set = isl_set_from_cloog_domain(domain);
1899 isl_constraint *c;
1900 isl_constraint *eq;
1902 c = cloog_constraint_to_isl(lb);
1903 aff = isl_constraint_get_bound(c, isl_dim_set, level - 1);
1904 aff = isl_aff_ceil(aff);
1905 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, level - 1, -1);
1906 aff = isl_aff_add_constant(aff, offset);
1907 eq = isl_equality_from_aff(aff);
1908 set = isl_set_add_constraint(set, eq);
1910 return cloog_domain_from_isl_set(set);