Avoid use of undocumented isl_*_print functions
[cloog.git] / source / isl / domain.c
blobfbc02553c25f4bd036de2ba89e1ab7c359b574f8
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/lp.h>
11 #include <isl/aff.h>
12 #include <isl/map.h>
13 #include <isl/val.h>
14 #include <isl/val_gmp.h>
16 #ifdef OSL_SUPPORT
17 #include <osl/macros.h>
18 #include <osl/relation.h>
19 #endif
21 CloogDomain *cloog_domain_from_isl_set(__isl_take isl_set *set)
23 if (isl_set_is_params(set))
24 set = isl_set_from_params(set);
25 set = isl_set_detect_equalities(set);
26 set = isl_set_compute_divs(set);
27 return (CloogDomain *)set;
30 __isl_give isl_set *isl_set_from_cloog_domain(CloogDomain *domain)
32 return (isl_set *)domain;
35 CloogScattering *cloog_scattering_from_isl_map(__isl_take isl_map *map)
37 return (CloogScattering *)map;
40 __isl_give isl_map *isl_map_from_cloog_scattering(CloogScattering *scattering)
42 return (isl_map *)scattering;
46 /**
47 * Returns true if each scattering dimension is defined in terms
48 * of the original iterators.
50 int cloog_scattering_fully_specified(CloogScattering *scattering,
51 CloogDomain *domain)
53 isl_map *map = isl_map_from_cloog_scattering(scattering);
54 return isl_map_is_single_valued(map);
58 CloogConstraintSet *cloog_domain_constraints(CloogDomain *domain)
60 isl_basic_set *bset;
61 isl_set *set = isl_set_from_cloog_domain(domain);
62 assert(isl_set_n_basic_set(set) == 1);
63 bset = isl_set_copy_basic_set(set);
64 return cloog_constraint_set_from_isl_basic_set(bset);
68 void cloog_domain_print_constraints(FILE *foo, CloogDomain *domain,
69 int print_number)
71 isl_printer *p;
72 isl_basic_set *bset;
73 isl_set *set = isl_set_from_cloog_domain(domain);
75 p = isl_printer_to_file(isl_set_get_ctx(set), foo);
76 if (print_number) {
77 p = isl_printer_set_output_format(p, ISL_FORMAT_EXT_POLYLIB);
78 p = isl_printer_print_set(p, set);
79 } else {
80 assert(isl_set_n_basic_set(set) == 1);
81 bset = isl_set_copy_basic_set(set);
82 p = isl_printer_set_output_format(p, ISL_FORMAT_POLYLIB);
83 p = isl_printer_print_basic_set(p, bset);
84 isl_basic_set_free(bset);
86 isl_printer_free(p);
90 void cloog_scattering_print_constraints(FILE *foo, CloogScattering *scattering)
92 isl_map *map = isl_map_from_cloog_scattering(scattering);
93 isl_printer *p;
95 p = isl_printer_to_file(isl_map_get_ctx(map), foo);
96 p = isl_printer_set_output_format(p, ISL_FORMAT_EXT_POLYLIB);
97 p = isl_printer_print_map(p, map);
98 isl_printer_free(p);
102 void cloog_domain_free(CloogDomain * domain)
104 isl_set *set = isl_set_from_cloog_domain(domain);
105 isl_set_free(set);
109 void cloog_scattering_free(CloogScattering *scatt)
111 isl_map *map = isl_map_from_cloog_scattering(scatt);
112 isl_map_free(map);
116 CloogDomain * cloog_domain_copy(CloogDomain * domain)
118 isl_set *set = isl_set_from_cloog_domain(domain);
119 return cloog_domain_from_isl_set(isl_set_copy(set));
124 * cloog_domain_convex function:
125 * Computes the convex hull of domain.
127 CloogDomain *cloog_domain_convex(CloogDomain *domain)
129 isl_set *set = isl_set_from_cloog_domain(domain);
130 set = isl_set_from_basic_set(isl_set_convex_hull(isl_set_copy(set)));
131 return cloog_domain_from_isl_set(set);
136 * cloog_domain_simple_convex:
137 * Given a list (union) of polyhedra, this function returns a "simple"
138 * convex hull of this union. In particular, the constraints of the
139 * the returned polyhedron consist of (parametric) lower and upper
140 * bounds on individual variables and constraints that appear in the
141 * original polyhedra.
143 CloogDomain *cloog_domain_simple_convex(CloogDomain *domain)
145 struct isl_basic_set *hull;
146 isl_set *set = isl_set_from_cloog_domain(domain);
148 if (cloog_domain_isconvex(domain))
149 return cloog_domain_copy(domain);
151 hull = isl_set_bounded_simple_hull(isl_set_copy(set));
152 return cloog_domain_from_isl_set(isl_set_from_basic_set(hull));
157 * cloog_domain_simplify function:
158 * Given two polyhedral domains (dom1) and (dom2),
159 * this function finds the largest domain set (or the smallest list
160 * of non-redundant constraints), that when intersected with polyhedral
161 * domain (dom2) equals (dom1)intersect(dom2). The output is a new CloogDomain
162 * structure with a polyhedral domain with the "redundant" constraints removed.
163 * NB: the second domain is required not to be a union.
165 CloogDomain *cloog_domain_simplify(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_gist(isl_set_copy(set1), isl_set_copy(set2));
170 return cloog_domain_from_isl_set(set1);
175 * cloog_domain_union function:
176 * This function returns a new polyhedral domain which is the union of
177 * two polyhedral domains (dom1) U (dom2).
178 * Frees dom1 and dom2;
180 CloogDomain *cloog_domain_union(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_union(set1, set2);
185 return cloog_domain_from_isl_set(set1);
191 * cloog_domain_intersection function:
192 * This function returns a new polyhedral domain which is the intersection of
193 * two polyhedral domains (dom1) \cap (dom2).
195 CloogDomain *cloog_domain_intersection(CloogDomain *dom1, CloogDomain *dom2)
197 isl_set *set1 = isl_set_from_cloog_domain(dom1);
198 isl_set *set2 = isl_set_from_cloog_domain(dom2);
199 set1 = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
200 return cloog_domain_from_isl_set(set1);
205 * cloog_domain_difference function:
206 * Returns the set difference domain \ minus.
208 CloogDomain *cloog_domain_difference(CloogDomain *domain, CloogDomain *minus)
210 isl_set *set1 = isl_set_from_cloog_domain(domain);
211 isl_set *set2 = isl_set_from_cloog_domain(minus);
212 set1 = isl_set_subtract(isl_set_copy(set1), isl_set_copy(set2));
213 return cloog_domain_from_isl_set(set1);
218 * cloog_domain_sort function:
219 * This function topologically sorts (nb_doms) domains. Here (doms) is an
220 * array of pointers to CloogDomains, (nb_doms) is the number of domains,
221 * (level) is the level to consider for partial ordering (nb_par) is the
222 * parameter space dimension, (permut) if not NULL, is an array of (nb_doms)
223 * integers that contains a permutation specification after call in order to
224 * apply the topological sorting.
226 void cloog_domain_sort(CloogDomain **doms, unsigned nb_doms, unsigned level,
227 int *permut)
229 int i, j, k, cmp;
230 struct isl_ctx *ctx;
231 unsigned char **follows;
232 isl_set *set_i, *set_j;
233 isl_basic_set *bset_i, *bset_j;
235 if (!nb_doms)
236 return;
237 set_i = isl_set_from_cloog_domain(doms[0]);
238 ctx = isl_set_get_ctx(set_i);
239 for (i = 0; i < nb_doms; i++) {
240 set_i = isl_set_from_cloog_domain(doms[i]);
241 assert(isl_set_n_basic_set(set_i) == 1);
244 follows = isl_alloc_array(ctx, unsigned char *, nb_doms);
245 assert(follows);
246 for (i = 0; i < nb_doms; ++i) {
247 follows[i] = isl_alloc_array(ctx, unsigned char, nb_doms);
248 assert(follows[i]);
249 for (j = 0; j < nb_doms; ++j)
250 follows[i][j] = 0;
253 for (i = 1; i < nb_doms; ++i) {
254 for (j = 0; j < i; ++j) {
255 if (follows[i][j] || follows[j][i])
256 continue;
257 set_i = isl_set_from_cloog_domain(doms[i]);
258 set_j = isl_set_from_cloog_domain(doms[j]);
259 bset_i = isl_set_copy_basic_set(set_i);
260 bset_j = isl_set_copy_basic_set(set_j);
261 cmp = isl_basic_set_compare_at(bset_i, bset_j, level-1);
262 isl_basic_set_free(bset_i);
263 isl_basic_set_free(bset_j);
264 if (!cmp)
265 continue;
266 if (cmp > 0) {
267 follows[i][j] = 1;
268 for (k = 0; k < i; ++k)
269 follows[i][k] |= follows[j][k];
270 } else {
271 follows[j][i] = 1;
272 for (k = 0; k < i; ++k)
273 follows[k][i] |= follows[k][j];
278 for (i = 0, j = 0; i < nb_doms; j = (j + 1) % nb_doms) {
279 for (k = 0; k < nb_doms; ++k)
280 if (follows[j][k])
281 break;
282 if (k < nb_doms)
283 continue;
284 for (k = 0; k < nb_doms; ++k)
285 follows[k][j] = 0;
286 follows[j][j] = 1;
287 permut[i] = 1 + j;
288 ++i;
291 for (i = 0; i < nb_doms; ++i)
292 free(follows[i]);
293 free(follows);
298 * Check whether there is or may be any value of dom1 at the given level
299 * that is greater than or equal to a value of dom2 at the same level.
301 * Return
302 * 1 is there is or may be a greater-than pair.
303 * 0 if there is no greater-than pair, but there may be an equal-to pair
304 * -1 if there is definitely no such pair
306 int cloog_domain_follows(CloogDomain *dom1, CloogDomain *dom2, unsigned level)
308 isl_set *set1 = isl_set_from_cloog_domain(dom1);
309 isl_set *set2 = isl_set_from_cloog_domain(dom2);
310 int follows;
312 follows = isl_set_follows_at(set1, set2, level - 1);
313 assert(follows >= -1);
315 return follows;
320 * cloog_domain_empty function:
321 * Returns an empty domain of the same dimensions as template.
323 CloogDomain *cloog_domain_empty(CloogDomain *template)
325 isl_set *set = isl_set_from_cloog_domain(template);
326 isl_space *space = isl_set_get_space(set);
327 return cloog_domain_from_isl_set(isl_set_empty(space));
332 * Return 1 if the specified dimension has both an upper and a lower bound.
334 int cloog_domain_is_bounded(CloogDomain *dom, unsigned level)
336 isl_set *set = isl_set_from_cloog_domain(dom);
337 return isl_set_dim_is_bounded(set, isl_dim_set, level - 1);
341 /******************************************************************************
342 * Structure display function *
343 ******************************************************************************/
347 * cloog_domain_print_structure :
348 * this function is a more human-friendly way to display the CloogDomain data
349 * structure, it only shows the constraint system and includes an indentation
350 * level (level) in order to work with others print_structure functions.
352 void cloog_domain_print_structure(FILE *file, CloogDomain *domain, int level,
353 const char *name)
355 int i ;
356 isl_set *set = isl_set_from_cloog_domain(domain);
357 isl_printer *p;
359 /* Go to the right level. */
360 for (i = 0; i < level; i++)
361 fprintf(file, "|\t");
363 if (!set) {
364 fprintf(file, "+-- Null CloogDomain\n");
365 return;
367 fprintf(file, "+-- %s\n", name);
368 for (i = 0; i < level+1; ++i)
369 fprintf(file, "|\t");
371 p = isl_printer_to_file(isl_set_get_ctx(set), file);
372 p = isl_printer_print_set(p, set);
373 isl_printer_free(p);
375 fprintf(file, "\n");
379 /******************************************************************************
380 * Memory deallocation function *
381 ******************************************************************************/
384 void cloog_domain_list_free(CloogDomainList *list)
386 CloogDomainList *next;
388 for ( ; list; list = next) {
389 next = list->next;
390 cloog_domain_free(list->domain);
391 free(list);
397 * cloog_scattering_list_free function:
398 * This function frees the allocated memory for a CloogScatteringList structure.
400 void cloog_scattering_list_free(CloogScatteringList *list)
402 while (list != NULL) {
403 CloogScatteringList *temp = list->next;
404 isl_map *map = isl_map_from_cloog_scattering(list->scatt);
405 isl_map_free(map);
406 free(list);
407 list = temp;
412 /******************************************************************************
413 * Reading function *
414 ******************************************************************************/
418 * cloog_domain_read_context function:
419 * Read parameter domain.
421 CloogDomain *cloog_domain_read_context(CloogState *state, FILE *input)
423 struct isl_ctx *ctx = state->backend->ctx;
424 isl_set *set;
426 set = isl_set_read_from_file(ctx, input);
427 set = isl_set_move_dims(set, isl_dim_param, 0,
428 isl_dim_set, 0, isl_set_dim(set, isl_dim_set));
430 return cloog_domain_from_isl_set(set);
435 * cloog_domain_from_context
436 * Reinterpret context by turning parameters into variables.
438 CloogDomain *cloog_domain_from_context(CloogDomain *context)
440 isl_set *set = isl_set_from_cloog_domain(context);
442 set = isl_set_move_dims(set, isl_dim_set, 0,
443 isl_dim_param, 0, isl_set_dim(set, isl_dim_param));
445 return cloog_domain_from_isl_set(set);
450 * cloog_domain_union_read function:
451 * This function reads a union of polyhedra into a file (input) and
452 * returns a pointer to a CloogDomain containing the read information.
454 CloogDomain *cloog_domain_union_read(CloogState *state,
455 FILE *input, int nb_parameters)
457 struct isl_ctx *ctx = state->backend->ctx;
458 struct isl_set *set;
460 set = isl_set_read_from_file(ctx, input);
461 if (isl_set_dim(set, isl_dim_param) != nb_parameters) {
462 int dim = isl_set_dim(set, isl_dim_set);
463 set = isl_set_move_dims(set, isl_dim_param, 0,
464 isl_dim_set, dim - nb_parameters, nb_parameters);
466 return cloog_domain_from_isl_set(set);
471 * cloog_domain_read_scattering function:
472 * This function reads in a scattering function from the file input.
474 * We try to read the scattering relation as a map, but if it is
475 * specified in the original PolyLib format, then isl_map_read_from_file
476 * will treat the input as a set return a map with zero input dimensions.
477 * In this case, we need to decompose the set into a map from
478 * scattering dimensions to domain dimensions and then invert the
479 * resulting map.
481 CloogScattering *cloog_domain_read_scattering(CloogDomain *domain, FILE *input)
483 isl_set *set = isl_set_from_cloog_domain(domain);
484 isl_ctx *ctx = isl_set_get_ctx(set);
485 struct isl_map *scat;
486 unsigned nparam;
487 unsigned dim;
488 unsigned n_scat;
490 dim = isl_set_dim(set, isl_dim_set);
491 nparam = isl_set_dim(set, isl_dim_param);
492 scat = isl_map_read_from_file(ctx, input);
493 if (isl_map_dim(scat, isl_dim_param) != nparam) {
494 int n_out = isl_map_dim(scat, isl_dim_out);
495 scat = isl_map_move_dims(scat, isl_dim_param, 0,
496 isl_dim_out, n_out - nparam, nparam);
498 if (isl_map_dim(scat, isl_dim_in) != dim) {
499 n_scat = isl_map_dim(scat, isl_dim_out) - dim;
500 scat = isl_map_move_dims(scat, isl_dim_in, 0,
501 isl_dim_out, n_scat, dim);
503 return cloog_scattering_from_isl_map(scat);
506 /******************************************************************************
507 * CloogMatrix Reading function *
508 ******************************************************************************/
511 * isl_constraint_read_from_matrix:
512 * Convert a single line of a matrix to a isl_constraint.
513 * Returns a pointer to the constraint if successful; NULL otherwise.
515 static struct isl_constraint *isl_constraint_read_from_matrix(
516 struct isl_space *dim, cloog_int_t *row)
518 struct isl_constraint *constraint;
519 int j;
520 int nvariables = isl_space_dim(dim, isl_dim_set);
521 int nparam = isl_space_dim(dim, isl_dim_param);
522 isl_local_space *ls = isl_local_space_from_space(dim);
524 if (cloog_int_is_zero(row[0]))
525 constraint = isl_equality_alloc(ls);
526 else
527 constraint = isl_inequality_alloc(ls);
529 for (j = 0; j < nvariables; ++j) {
530 isl_val *val = cloog_int_to_isl_val(isl_constraint_get_ctx(constraint), row[1 + j]);
531 isl_constraint_set_coefficient_val(constraint, isl_dim_out, j, val);
534 for (j = 0; j < nparam; ++j) {
535 isl_val *val = cloog_int_to_isl_val(isl_constraint_get_ctx(constraint), row[1 + nvariables + j]);
536 isl_constraint_set_coefficient_val(constraint, isl_dim_param, j, val);
539 isl_val *val = cloog_int_to_isl_val(isl_constraint_get_ctx(constraint), row[1 + nvariables + nparam]);
540 isl_constraint_set_constant_val(constraint, val);
542 return constraint;
546 * isl_basic_set_read_from_matrix:
547 * Convert matrix to basic_set. The matrix contains nparam parameter columns.
548 * Returns a pointer to the basic_set if successful; NULL otherwise.
550 static struct isl_basic_set *isl_basic_set_read_from_matrix(struct isl_ctx *ctx,
551 CloogMatrix* matrix, int nparam)
553 struct isl_space *dim;
554 struct isl_basic_set *bset;
555 int i;
556 unsigned nrows, ncolumns;
558 nrows = matrix->NbRows;
559 ncolumns = matrix->NbColumns;
560 int nvariables = ncolumns - 2 - nparam;
562 dim = isl_space_set_alloc(ctx, nparam, nvariables);
564 bset = isl_basic_set_universe(isl_space_copy(dim));
566 for (i = 0; i < nrows; ++i) {
567 cloog_int_t *row = matrix->p[i];
568 struct isl_constraint *constraint =
569 isl_constraint_read_from_matrix(isl_space_copy(dim), row);
570 bset = isl_basic_set_add_constraint(bset, constraint);
573 isl_space_free(dim);
575 return bset;
579 * cloog_domain_from_cloog_matrix:
580 * Create a CloogDomain containing the constraints described in matrix.
581 * nparam is the number of parameters contained in the domain.
582 * Returns a pointer to the CloogDomain if successful; NULL otherwise.
584 CloogDomain *cloog_domain_from_cloog_matrix(CloogState *state,
585 CloogMatrix *matrix, int nparam)
587 struct isl_ctx *ctx = state->backend->ctx;
588 struct isl_basic_set *bset;
590 bset = isl_basic_set_read_from_matrix(ctx, matrix, nparam);
592 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
596 * cloog_scattering_from_cloog_matrix:
597 * Create a CloogScattering containing the constraints described in matrix.
598 * nparam is the number of parameters contained in the domain.
599 * Returns a pointer to the CloogScattering if successful; NULL otherwise.
601 CloogScattering *cloog_scattering_from_cloog_matrix(CloogState *state,
602 CloogMatrix *matrix, int nb_scat, int nb_par)
604 struct isl_ctx *ctx = state->backend->ctx;
605 struct isl_basic_set *bset;
606 struct isl_basic_map *scat;
607 struct isl_space *dims;
608 unsigned dim;
610 bset = isl_basic_set_read_from_matrix(ctx, matrix, nb_par);
611 dim = isl_basic_set_n_dim(bset) - nb_scat;
612 dims = isl_space_alloc(ctx, nb_par, nb_scat, dim);
614 scat = isl_basic_map_from_basic_set(bset, dims);
615 scat = isl_basic_map_reverse(scat);
616 return cloog_scattering_from_isl_map(isl_map_from_basic_map(scat));
620 /******************************************************************************
621 * Processing functions *
622 ******************************************************************************/
625 #ifdef OSL_SUPPORT
627 * Converts an openscop relation to a CLooG domain.
628 * \param[in,out] state CLooG state.
629 * \param[in] relation OpenScop relation to convert.
630 * \return A new CloogDomain corresponding to the input OpenScop relation.
632 CloogDomain *cloog_domain_from_osl_relation(CloogState *state,
633 osl_relation_p relation) {
634 char *str;
635 struct isl_ctx *ctx = state->backend->ctx;
636 isl_set *set;
637 CloogDomain *domain = NULL;
639 if (relation != NULL) {
640 str = osl_relation_spprint_polylib(relation, NULL);
641 set = isl_set_read_from_str(ctx, str);
642 free(str);
644 domain = cloog_domain_from_isl_set(set);
647 return domain;
651 * Converts an openscop scattering relation to a CLooG scattering.
652 * \param[in,out] state CLooG state.
653 * \param[in] relation OpenScop relation to convert.
654 * \return A new CloogScattering corresponding to the input OpenScop relation.
656 CloogScattering *cloog_scattering_from_osl_relation(CloogState *state,
657 osl_relation_p relation) {
658 char *str;
659 struct isl_ctx *ctx = state->backend->ctx;
660 isl_map *map;
661 CloogScattering *scattering = NULL;
663 if (relation != NULL) {
664 if (relation->type != OSL_TYPE_SCATTERING)
665 cloog_die("Cannot convert a non-scattering relation to a scattering.\n");
667 str = osl_relation_spprint_polylib(relation, NULL);
668 map = isl_map_read_from_str(ctx, str);
669 free(str);
671 scattering = cloog_scattering_from_isl_map(map);
674 return scattering;
676 #endif
679 * cloog_domain_isempty function:
681 int cloog_domain_isempty(CloogDomain *domain)
683 isl_set *set = isl_set_from_cloog_domain(domain);
684 return isl_set_is_empty(set);
689 * cloog_domain_universe function:
690 * This function returns the complete dim-dimensional space.
692 CloogDomain *cloog_domain_universe(CloogState *state, unsigned dim)
694 struct isl_space *dims;
695 struct isl_basic_set *bset;
697 dims = isl_space_set_alloc(state->backend->ctx, 0, dim);
698 bset = isl_basic_set_universe(dims);
699 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
704 * cloog_domain_project function:
705 * This function returns the projection of
706 * (domain) on the (level) first dimensions (i.e. outer loops).
708 CloogDomain *cloog_domain_project(CloogDomain *domain, int level)
710 isl_set *set = isl_set_from_cloog_domain(domain);
711 set = isl_set_remove_dims(isl_set_copy(set), isl_dim_set,
712 level, isl_set_n_dim(set) - level);
713 set = isl_set_compute_divs(set);
714 if (level > 0)
715 set = isl_set_remove_divs_involving_dims(set,
716 isl_dim_set, level - 1, 1);
717 return cloog_domain_from_isl_set(set);
722 * cloog_domain_extend function:
723 * This function returns the (domain) given as input with (dim)
724 * dimensions and (nb_par) parameters.
725 * This function does not free (domain), and returns a new CloogDomain.
727 CloogDomain *cloog_domain_extend(CloogDomain *domain, int dim)
729 isl_set *set = isl_set_from_cloog_domain(domain);
730 int n = isl_set_dim(set, isl_dim_set);
731 set = isl_set_add_dims(isl_set_copy(set), isl_dim_set, dim - n);
732 return cloog_domain_from_isl_set(set);
737 * cloog_domain_never_integral function:
738 * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0.
739 * There is no need to check for such constraints explicitly for the isl
740 * backend.
742 int cloog_domain_never_integral(CloogDomain * domain)
744 isl_set *set = isl_set_from_cloog_domain(domain);
745 return isl_set_is_empty(set);
750 * Check whether the loop at "level" is executed at most once.
751 * We construct a map that maps all remaining variables to this iterator
752 * and check whether this map is single valued.
754 * Alternatively, we could have mapped the domain through a mapping
755 * [p] -> { [..., i] -> [..., i'] : i' > i }
756 * and then taken the intersection of the original domain and the transformed
757 * domain. If this intersection is empty, then the corresponding
758 * loop is executed at most once.
760 int cloog_domain_is_otl(CloogDomain *domain, int level)
762 int otl;
763 isl_set *set = isl_set_from_cloog_domain(domain);
764 isl_map *map;
766 map = isl_map_from_domain(isl_set_copy(set));
767 map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_in, level - 1, 1);
768 otl = isl_map_is_single_valued(map);
769 isl_map_free(map);
771 return otl;
776 * cloog_domain_stride function:
777 * This function finds the stride imposed to unknown with the column number
778 * 'strided_level' in order to be integral. For instance, if we have a
779 * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral
780 * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to
781 * the unknown i. The function returns the imposed stride in a parameter field.
782 * - domain is the set of constraint we have to consider,
783 * - strided_level is the column number of the unknown for which a stride have
784 * to be found,
785 * - looking_level is the column number of the unknown that impose a stride to
786 * the first unknown.
787 * - stride is the stride that is returned back as a function parameter.
788 * - offset is the value of the constant c if the condition is of the shape
789 * (i + c)%s = 0, s being the stride.
791 void cloog_domain_stride(CloogDomain *domain, int strided_level,
792 cloog_int_t *stride, cloog_int_t *offset)
794 int ret = -1;
795 isl_set *set = isl_set_from_cloog_domain(domain);
796 isl_val *stride_val = NULL;
797 isl_val *offset_val = NULL;
798 ret = isl_set_dim_residue_class_val(set, strided_level - 1, &stride_val, &offset_val);
799 if (ret != 0)
800 cloog_die("failure to compute stride.\n");
801 isl_val_to_cloog_int(stride_val, stride);
802 isl_val_to_cloog_int(offset_val, offset);
804 if (!cloog_int_is_zero(*offset))
805 cloog_int_sub(*offset, *stride, *offset);
807 isl_val_free(stride_val);
808 isl_val_free(offset_val);
810 return;
814 struct cloog_can_stride {
815 int level;
816 int can_stride;
819 static int constraint_can_stride(__isl_take isl_constraint *c, void *user)
821 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
822 int i;
823 isl_val *v;
824 unsigned n_div;
826 if (isl_constraint_is_equality(c)) {
827 isl_constraint_free(c);
828 return 0;
831 v = isl_constraint_get_coefficient_val(c, isl_dim_set, ccs->level - 1);
832 if (isl_val_is_pos(v)) {
833 n_div = isl_constraint_dim(c, isl_dim_div);
835 for (i = 0; i < n_div; ++i) {
836 isl_val_free(v);
837 v = isl_constraint_get_coefficient_val(c, isl_dim_div, i);
838 if (!isl_val_is_zero(v))
839 break;
841 if (i < n_div)
842 ccs->can_stride = 0;
844 isl_val_free(v);
846 isl_constraint_free(c);
847 return 0;
850 static int basic_set_can_stride(__isl_take isl_basic_set *bset, void *user)
852 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
853 int r;
855 r = isl_basic_set_foreach_constraint(bset, constraint_can_stride, ccs);
856 isl_basic_set_free(bset);
857 return r;
862 * Return 1 if CLooG is allowed to perform stride detection on level "level"
863 * and 0 otherwise.
864 * Currently, stride detection is only allowed when none of the lower
865 * bound constraints involve any existentially quantified variables.
866 * The reason is that the current isl interface does not make it
867 * easy to construct an integer division that depends on other integer
868 * divisions.
869 * By not allowing existentially quantified variables in the constraints,
870 * we can ignore them in cloog_domain_stride_lower_bound.
872 int cloog_domain_can_stride(CloogDomain *domain, int level)
874 struct cloog_can_stride ccs = { level, 1 };
875 isl_set *set = isl_set_from_cloog_domain(domain);
876 int r;
877 r = isl_set_foreach_basic_set(set, basic_set_can_stride, &ccs);
878 assert(r == 0);
879 return ccs.can_stride;
883 struct cloog_stride_lower {
884 int level;
885 CloogStride *stride;
886 isl_set *set;
887 isl_basic_set *bounds;
890 /* If the given constraint is a lower bound on csl->level, then add
891 * a lower bound to csl->bounds that makes sure that the remainder
892 * of the smallest value on division by csl->stride is equal to csl->offset.
894 * In particular, the given lower bound is of the form
896 * a i + f >= 0
898 * where f may depend on the parameters and other iterators.
899 * The stride is s and the offset is d.
900 * The lower bound -f/a may not satisfy the above condition. In fact,
901 * it may not even be integral. We want to round this value of i up
902 * to the nearest value that satisfies the condition and add the corresponding
903 * lower bound constraint. This nearest value is obtained by rounding
904 * i - d up to the nearest multiple of s.
905 * That is, we first subtract d
907 * i' = -f/a - d
909 * then we round up to the nearest multiple of s
911 * i'' = s * ceil(i'/s)
913 * and finally, we add d again
915 * i''' = i'' + d
917 * and impose the constraint i >= i'''.
919 * We find
921 * i'' = s * ceil((-f - a * d)/(a * s)) = - s * floor((f + a * d)/(a * s))
923 * i >= - s * floor((f + a * d)/(a * s)) + d
925 * or
926 * i + s * floor((f + a * d)/(a * s)) - d >= 0
928 static int constraint_stride_lower(__isl_take isl_constraint *c, void *user)
930 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
931 isl_val *v;
932 isl_constraint *bound;
933 isl_aff *b;
935 if (isl_constraint_is_equality(c)) {
936 isl_constraint_free(c);
937 return 0;
940 v = isl_constraint_get_coefficient_val(c, isl_dim_set, csl->level - 1);
941 if (!isl_val_is_pos(v)) {
942 isl_val_free(v);
943 isl_constraint_free(c);
945 return 0;
947 isl_val_free(v);
949 b = isl_constraint_get_bound(c, isl_dim_set, csl->level - 1);
951 b = isl_aff_neg(b);
952 b = isl_aff_add_constant_val(b, cloog_int_to_isl_val(isl_constraint_get_ctx(c), csl->stride->offset));
953 b = isl_aff_scale_down_val(b, cloog_int_to_isl_val(isl_constraint_get_ctx(c), csl->stride->stride));
954 b = isl_aff_floor(b);
955 b = isl_aff_scale_val(b, cloog_int_to_isl_val(isl_constraint_get_ctx(c), csl->stride->stride));
956 v = cloog_int_to_isl_val(isl_constraint_get_ctx(c), csl->stride->offset);
957 v = isl_val_neg(v);
958 b = isl_aff_add_constant_val(b, v);
959 b = isl_aff_add_coefficient_si(b, isl_dim_in, csl->level - 1, 1);
961 bound = isl_inequality_from_aff(b);
963 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
965 isl_constraint_free(c);
967 return 0;
970 /* This functions performs essentially the same operation as
971 * constraint_stride_lower, the only difference being that the offset d
972 * is not a constant, but an affine expression in terms of the parameters
973 * and earlier variables. In particular the affine expression is equal
974 * to the coefficients of stride->constraint multiplied by stride->factor.
975 * As in constraint_stride_lower, we add an extra bound
977 * i + s * floor((f + a * d)/(a * s)) - d >= 0
979 * for each lower bound
981 * a i + f >= 0
983 * where d is not the aforementioned affine expression.
985 static int constraint_stride_lower_c(__isl_take isl_constraint *c, void *user)
987 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
988 isl_val *v;
989 isl_constraint *bound;
990 isl_constraint *csl_c;
991 isl_aff *d, *b;
993 if (isl_constraint_is_equality(c)) {
994 isl_constraint_free(c);
995 return 0;
998 v = isl_constraint_get_coefficient_val(c, isl_dim_set, csl->level - 1);
999 if (!isl_val_is_pos(v)) {
1000 isl_val_free(v);
1001 isl_constraint_free(c);
1003 return 0;
1006 csl_c = cloog_constraint_to_isl(csl->stride->constraint);
1008 d = isl_constraint_get_aff(csl_c);
1009 d = isl_aff_drop_dims(d, isl_dim_div, 0, isl_aff_dim(d, isl_dim_div));
1010 d = isl_aff_set_coefficient_si(d, isl_dim_in, csl->level - 1, 0);
1011 d = isl_aff_scale_val(d, cloog_int_to_isl_val(isl_constraint_get_ctx(csl_c), csl->stride->factor));
1013 b = isl_constraint_get_bound(c, isl_dim_set, csl->level - 1);
1015 b = isl_aff_neg(b);
1016 b = isl_aff_add(b, isl_aff_copy(d));
1017 b = isl_aff_scale_down_val(b, cloog_int_to_isl_val(isl_constraint_get_ctx(csl_c), csl->stride->stride));
1018 b = isl_aff_floor(b);
1019 b = isl_aff_scale_val(b, cloog_int_to_isl_val(isl_constraint_get_ctx(csl_c), csl->stride->stride));
1020 b = isl_aff_sub(b, d);
1021 b = isl_aff_add_coefficient_si(b, isl_dim_in, csl->level - 1, 1);
1023 bound = isl_inequality_from_aff(b);
1025 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
1027 isl_val_free(v);
1028 isl_constraint_free(c);
1030 return 0;
1033 static int basic_set_stride_lower(__isl_take isl_basic_set *bset, void *user)
1035 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
1036 int r;
1038 csl->bounds = isl_basic_set_universe(isl_basic_set_get_space(bset));
1039 if (csl->stride->constraint)
1040 r = isl_basic_set_foreach_constraint(bset,
1041 &constraint_stride_lower_c, csl);
1042 else
1043 r = isl_basic_set_foreach_constraint(bset,
1044 &constraint_stride_lower, csl);
1045 bset = isl_basic_set_intersect(bset, csl->bounds);
1046 csl->set = isl_set_union(csl->set, isl_set_from_basic_set(bset));
1048 return r;
1052 * Update the lower bounds at level "level" to the given stride information.
1053 * That is, make sure that the remainder on division by "stride"
1054 * is equal to "offset".
1056 CloogDomain *cloog_domain_stride_lower_bound(CloogDomain *domain, int level,
1057 CloogStride *stride)
1059 struct cloog_stride_lower csl;
1060 isl_set *set = isl_set_from_cloog_domain(domain);
1061 int r;
1063 csl.stride = stride;
1064 csl.level = level;
1065 csl.set = isl_set_empty(isl_set_get_space(set));
1067 r = isl_set_foreach_basic_set(set, basic_set_stride_lower, &csl);
1068 assert(r == 0);
1070 cloog_domain_free(domain);
1071 return cloog_domain_from_isl_set(csl.set);
1075 /* Add stride constraint, if any, to domain.
1077 CloogDomain *cloog_domain_add_stride_constraint(CloogDomain *domain,
1078 CloogStride *stride)
1080 isl_constraint *c;
1081 isl_set *set;
1083 if (!stride || !stride->constraint)
1084 return domain;
1086 set = isl_set_from_cloog_domain(domain);
1087 c = isl_constraint_copy(cloog_constraint_to_isl(stride->constraint));
1089 set = isl_set_add_constraint(set, c);
1091 return cloog_domain_from_isl_set(set);
1096 * cloog_domain_lazy_equal function:
1097 * This function returns 1 if the domains given as input are the same, 0 if it
1098 * is unable to decide.
1100 int cloog_domain_lazy_equal(CloogDomain *d1, CloogDomain *d2)
1102 isl_set *set1 = isl_set_from_cloog_domain(d1);
1103 isl_set *set2 = isl_set_from_cloog_domain(d2);
1104 return isl_set_plain_is_equal(set1, set2);
1107 struct cloog_bound_split {
1108 isl_set *set;
1109 int level;
1110 int lower;
1111 int upper;
1114 static int constraint_bound_split(__isl_take isl_constraint *c, void *user)
1116 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1117 isl_val *v;
1118 int i;
1119 int handle = 0;
1121 v = isl_constraint_get_coefficient_val(c, isl_dim_set, cbs->level - 1);
1122 if (!cbs->lower && isl_val_is_pos(v))
1123 cbs->lower = handle = 1;
1124 else if (!cbs->upper && isl_val_is_neg(v))
1125 cbs->upper = handle = 1;
1127 if (handle) {
1128 for (i = 0; i < isl_set_dim(cbs->set, isl_dim_param); ++i) {
1129 isl_val_free(v);
1130 v = isl_constraint_get_coefficient_val(c, isl_dim_param, i);
1131 if (isl_val_is_zero(v))
1132 continue;
1134 cbs->set = isl_set_split_dims(cbs->set,
1135 isl_dim_param, i, 1);
1138 isl_val_free(v);
1140 isl_constraint_free(c);
1141 return (cbs->lower && cbs->upper) ? -1 : 0;
1144 static int basic_set_bound_split(__isl_take isl_basic_set *bset, void *user)
1146 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1147 int r;
1149 cbs->lower = 0;
1150 cbs->upper = 0;
1151 r = isl_basic_set_foreach_constraint(bset, constraint_bound_split, cbs);
1152 isl_basic_set_free(bset);
1153 return ((!cbs->lower || !cbs->upper) && r < 0) ? -1 : 0;
1157 * Return a union of sets S_i such that the convex hull of "dom",
1158 * when intersected with one the sets S_i, will have an upper and
1159 * lower bound for the dimension at "level" (provided "dom" itself
1160 * has such bounds for the dimensions).
1162 * We currently take a very simple approach. For each of the basic
1163 * sets in "dom" we pick a lower and an upper bound and split the
1164 * range of any parameter involved in these two bounds in a
1165 * nonnegative and a negative part. This ensures that the symbolic
1166 * constant in these two constraints are themselves bounded and
1167 * so there will be at least one upper and one lower bound
1168 * in the convex hull.
1170 CloogDomain *cloog_domain_bound_splitter(CloogDomain *dom, int level)
1172 struct cloog_bound_split cbs;
1173 isl_set *set = isl_set_from_cloog_domain(dom);
1174 int r;
1175 cbs.level = level;
1176 cbs.set = isl_set_universe(isl_set_get_space(set));
1177 r = isl_set_foreach_basic_set(set, basic_set_bound_split, &cbs);
1178 assert(r == 0);
1179 return cloog_domain_from_isl_set(cbs.set);
1183 /* Check whether the union of scattering functions over all domains
1184 * is obviously injective.
1186 static int injective_scattering(CloogScatteringList *list)
1188 isl_map *map;
1189 isl_union_map *umap;
1190 int injective;
1191 int i = 0;
1192 char name[30];
1194 if (!list)
1195 return 1;
1197 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1198 snprintf(name, sizeof(name), "S%d", i);
1199 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1200 umap = isl_union_map_from_map(map);
1202 for (list = list->next, ++i; list; list = list->next, ++i) {
1203 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1204 snprintf(name, sizeof(name), "S%d", i);
1205 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1206 umap = isl_union_map_add_map(umap, map);
1209 injective = isl_union_map_plain_is_injective(umap);
1211 isl_union_map_free(umap);
1213 return injective;
1218 * cloog_scattering_lazy_block function:
1219 * This function returns 1 if the two scattering functions s1 and s2 given
1220 * as input are the same (except possibly for the final dimension, where we
1221 * allow a difference of 1), assuming that the domains on which this
1222 * scatterings are applied are the same.
1223 * In fact this function answers the question "can I
1224 * safely consider the two domains as only one with two statements (a block) ?".
1225 * A difference of 1 in the final dimension is only allowed if the
1226 * entire scattering function is injective.
1227 * - s1 and s2 are the two domains to check for blocking,
1228 * - scattering is the linked list of all domains,
1229 * - scattdims is the total number of scattering dimentions.
1231 int cloog_scattering_lazy_block(CloogScattering *s1, CloogScattering *s2,
1232 CloogScatteringList *scattering, int scattdims)
1234 int i;
1235 struct isl_space *dim;
1236 struct isl_map *rel;
1237 struct isl_set *delta;
1238 isl_map *map1 = isl_map_from_cloog_scattering(s1);
1239 isl_map *map2 = isl_map_from_cloog_scattering(s2);
1240 int block;
1241 isl_val *cst;
1242 unsigned n_scat;
1244 n_scat = isl_map_dim(map1, isl_dim_out);
1245 if (n_scat != isl_map_dim(map2, isl_dim_out))
1246 return 0;
1248 dim = isl_map_get_space(map1);
1249 dim = isl_space_map_from_set(isl_space_domain(dim));
1250 rel = isl_map_identity(dim);
1251 rel = isl_map_apply_domain(rel, isl_map_copy(map1));
1252 rel = isl_map_apply_range(rel, isl_map_copy(map2));
1253 delta = isl_map_deltas(rel);
1254 cst = NULL;
1255 for (i = 0; i < n_scat; ++i) {
1256 cst = isl_set_plain_get_val_if_fixed(delta, isl_dim_set, i);
1257 if (!cst){
1258 isl_val_free(cst);
1259 break;
1261 if (isl_val_is_zero(cst)){
1262 isl_val_free(cst);
1263 continue;
1265 if (i + 1 < n_scat){
1266 isl_val_free(cst);
1267 break;
1269 if (!isl_val_is_one(cst)){
1270 isl_val_free(cst);
1271 break;
1273 if (!injective_scattering(scattering)){
1274 isl_val_free(cst);
1275 break;
1278 isl_val_free(cst);
1280 block = i >= n_scat;
1281 isl_set_free(delta);
1282 return block;
1287 * cloog_domain_lazy_disjoint function:
1288 * This function returns 1 if the domains given as input are disjoint, 0 if it
1289 * is unable to decide.
1291 int cloog_domain_lazy_disjoint(CloogDomain *d1, CloogDomain *d2)
1293 isl_set *set1 = isl_set_from_cloog_domain(d1);
1294 isl_set *set2 = isl_set_from_cloog_domain(d2);
1295 return isl_set_plain_is_disjoint(set1, set2);
1300 * cloog_scattering_list_lazy_same function:
1301 * This function returns 1 if two domains in the list are the same, 0 if it
1302 * is unable to decide.
1304 int cloog_scattering_list_lazy_same(CloogScatteringList *list)
1306 CloogScatteringList *one, *other;
1307 isl_map *one_map, *other_map;
1309 for (one = list; one; one = one->next) {
1310 one_map = isl_map_from_cloog_scattering(one->scatt);
1311 for (other = one->next; other; other = other->next) {
1312 other_map = isl_map_from_cloog_scattering(other->scatt);
1313 if (isl_map_plain_is_equal(one_map, other_map))
1314 return 1;
1317 return 0;
1320 int cloog_domain_dimension(CloogDomain * domain)
1322 isl_set *set = isl_set_from_cloog_domain(domain);
1323 return isl_set_dim(set, isl_dim_set);
1326 int cloog_domain_parameter_dimension(CloogDomain *domain)
1328 isl_set *set = isl_set_from_cloog_domain(domain);
1329 return isl_set_dim(set, isl_dim_param);
1332 int cloog_scattering_dimension(CloogScattering *scatt, CloogDomain *domain)
1334 isl_map *map = isl_map_from_cloog_scattering(scatt);
1335 return isl_map_dim(map, isl_dim_out);
1338 int cloog_domain_isconvex(CloogDomain * domain)
1340 isl_set *set = isl_set_from_cloog_domain(domain);
1341 return isl_set_n_basic_set(set) <= 1;
1346 * cloog_domain_cut_first function:
1347 * This function splits off and returns the first convex set in the
1348 * union "domain". The remainder of the union is returned in rest.
1349 * The original "domain" itself is destroyed and may not be used
1350 * after a call to this function.
1352 CloogDomain *cloog_domain_cut_first(CloogDomain *domain, CloogDomain **rest)
1354 isl_set *set = isl_set_from_cloog_domain(domain);
1355 struct isl_basic_set *first;
1357 first = isl_set_copy_basic_set(set);
1358 set = isl_set_drop_basic_set(set, first);
1359 *rest = cloog_domain_from_isl_set(set);
1361 return cloog_domain_from_isl_set(isl_set_from_basic_set(first));
1366 * Given a union domain, try to find a simpler representation
1367 * using fewer sets in the union.
1368 * The original "domain" itself is destroyed and may not be used
1369 * after a call to this function.
1371 CloogDomain *cloog_domain_simplify_union(CloogDomain *domain)
1373 isl_set *set = isl_set_from_cloog_domain(domain);
1374 return cloog_domain_from_isl_set(isl_set_coalesce(set));
1379 * cloog_scattering_lazy_isscalar function:
1380 * this function returns 1 if the scattering dimension 'dimension' in the
1381 * scattering 'scatt' is constant.
1382 * If value is not NULL, then it is set to the constant value of dimension.
1384 int cloog_scattering_lazy_isscalar(CloogScattering *scatt, int dimension,
1385 cloog_int_t *value)
1387 isl_map *map = isl_map_from_cloog_scattering(scatt);
1388 isl_val *v = isl_map_plain_get_val_if_fixed(map, isl_dim_out, dimension);
1389 if (v != NULL) {
1390 if (!isl_val_is_nan(v)){
1391 if (value != NULL)
1392 isl_val_to_cloog_int(v, value);
1394 isl_val_free(v);
1395 return 1;
1397 else {
1398 isl_val_free(v);
1399 return 0;
1403 return 0;
1408 * cloog_domain_lazy_isconstant function:
1409 * this function returns 1 if the dimension 'dimension' in the
1410 * domain 'domain' is constant.
1411 * If value is not NULL, then it is set to the constant value of dimension.
1413 int cloog_domain_lazy_isconstant(CloogDomain *domain, int dimension,
1414 cloog_int_t *value)
1416 isl_set *set = isl_set_from_cloog_domain(domain);
1417 isl_val *cst = isl_set_plain_get_val_if_fixed(set, isl_dim_set, dimension);
1418 if (cst != NULL) {
1419 if (!isl_val_is_nan(cst)){
1420 if (value != NULL)
1421 isl_val_to_cloog_int(cst, value);
1423 isl_val_free(cst);
1424 return 1;
1426 else {
1427 isl_val_free(cst);
1428 return 0;
1432 return 0;
1437 * cloog_scattering_erase_dimension function:
1438 * this function returns a CloogDomain structure builds from 'domain' where
1439 * we removed the dimension 'dimension' and every constraint involving this
1440 * dimension.
1442 CloogScattering *cloog_scattering_erase_dimension(CloogScattering *scattering,
1443 int dimension)
1445 isl_map *map = isl_map_from_cloog_scattering(scattering);
1446 map = isl_map_remove_dims(isl_map_copy(map), isl_dim_out, dimension, 1);
1447 return cloog_scattering_from_isl_map(map);
1451 * cloog_domain_cube:
1452 * Construct and return a dim-dimensional cube, with values ranging
1453 * between min and max in each dimension.
1455 CloogDomain *cloog_domain_cube(CloogState *state,
1456 int dim, cloog_int_t min, cloog_int_t max)
1458 int i;
1459 isl_space *space;
1460 isl_set *cube;
1461 isl_val *min_v;
1462 isl_val *max_v;
1464 if (dim == 0)
1465 return cloog_domain_universe(state, dim);
1467 space = isl_space_set_alloc(state->backend->ctx, 0, dim);
1468 cube = isl_set_universe(space);
1469 for (i = 0; i < dim; ++i) {
1470 min_v = cloog_int_to_isl_val(isl_set_get_ctx(cube), min);
1471 max_v = cloog_int_to_isl_val(isl_set_get_ctx(cube), max);
1472 cube = isl_set_lower_bound_val(cube, isl_dim_set, i, min_v);
1473 cube = isl_set_upper_bound_val(cube, isl_dim_set, i, max_v);
1476 return cloog_domain_from_isl_set(cube);
1481 * cloog_domain_scatter function:
1482 * This function add the scattering (scheduling) informations to a domain.
1484 CloogDomain *cloog_domain_scatter(CloogDomain *domain, CloogScattering *scatt)
1486 isl_set *set = isl_set_from_cloog_domain(domain);
1487 isl_map *map = isl_map_from_cloog_scattering(scatt);
1489 map = isl_map_reverse(isl_map_copy(map));
1490 map = isl_map_intersect_range(map, set);
1491 set = isl_set_flatten(isl_map_wrap(map));
1492 return cloog_domain_from_isl_set(set);
1495 static int add_domain_from_map(__isl_take isl_map *map, void *user)
1497 isl_space *dim;
1498 const char *name;
1499 CloogDomain *domain;
1500 CloogScattering *scat;
1501 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1503 dim = isl_map_get_space(map);
1504 name = isl_space_get_tuple_name(dim, isl_dim_in);
1505 domain = cloog_domain_from_isl_set(isl_map_domain(isl_map_copy(map)));
1506 scat = cloog_scattering_from_isl_map(map);
1507 *ud = cloog_union_domain_add_domain(*ud, name, domain, scat, NULL);
1508 isl_space_free(dim);
1510 return 0;
1514 * Construct a CloogUnionDomain from an isl_union_map representing
1515 * a global scattering function. The input is a mapping from different
1516 * spaces (different tuple names and possibly different dimensions)
1517 * to a common space. The iteration domains are set to the domains
1518 * in each space. The statement names are set to the names of the
1519 * spaces. The parameter names of the result are set to those of
1520 * the input, but the iterator and scattering dimension names are
1521 * left unspecified.
1523 CloogUnionDomain *cloog_union_domain_from_isl_union_map(
1524 __isl_take isl_union_map *umap)
1526 int i;
1527 int nparam;
1528 isl_space *dim;
1529 CloogUnionDomain *ud;
1531 dim = isl_union_map_get_space(umap);
1532 nparam = isl_space_dim(dim, isl_dim_param);
1534 ud = cloog_union_domain_alloc(nparam);
1536 for (i = 0; i < nparam; ++i) {
1537 const char *s = isl_space_get_dim_name(dim, isl_dim_param, i);
1538 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1540 isl_space_free(dim);
1542 if (isl_union_map_foreach_map(umap, &add_domain_from_map, &ud) < 0) {
1543 isl_union_map_free(umap);
1544 cloog_union_domain_free(ud);
1545 assert(0);
1548 isl_union_map_free(umap);
1550 return ud;
1553 static int count_same_name(__isl_keep isl_space *dim,
1554 enum isl_dim_type type, unsigned pos, const char *name)
1556 enum isl_dim_type t;
1557 unsigned p, s;
1558 int count = 0;
1559 int len = strlen(name);
1561 for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) {
1562 s = t == type ? pos : isl_space_dim(dim, t);
1563 for (p = 0; p < s; ++p) {
1564 const char *n = isl_space_get_dim_name(dim, t, p);
1565 if (n && !strncmp(n, name, len))
1566 count++;
1569 return count;
1572 static CloogUnionDomain *add_domain(__isl_take isl_set *set, CloogUnionDomain *ud)
1574 int i, nvar;
1575 isl_ctx *ctx;
1576 isl_space *dim;
1577 char buffer[20];
1578 const char *name;
1579 CloogDomain *domain;
1581 ctx = isl_set_get_ctx(set);
1582 dim = isl_set_get_space(set);
1583 name = isl_space_get_tuple_name(dim, isl_dim_set);
1584 set = isl_set_flatten(set);
1585 set = isl_set_set_tuple_name(set, NULL);
1586 domain = cloog_domain_from_isl_set(set);
1587 ud = cloog_union_domain_add_domain(ud, name, domain, NULL, NULL);
1589 nvar = isl_space_dim(dim, isl_dim_set);
1590 for (i = 0; i < nvar; ++i) {
1591 char *long_name = NULL;
1592 int n;
1594 name = isl_space_get_dim_name(dim, isl_dim_set, i);
1595 if (!name) {
1596 snprintf(buffer, sizeof(buffer), "i%d", i);
1597 name = buffer;
1599 n = count_same_name(dim, isl_dim_set, i, name);
1600 if (n) {
1601 int size = strlen(name) + 10;
1602 long_name = isl_alloc_array(ctx, char, size);
1603 if (!long_name)
1604 cloog_die("memory overflow.\n");
1605 snprintf(long_name, size, "%s_%d", name, n);
1606 name = long_name;
1608 ud = cloog_union_domain_set_name(ud, CLOOG_ITER, i, name);
1609 free(long_name);
1611 isl_space_free(dim);
1613 return ud;
1617 * Construct a CloogUnionDomain from an isl_set.
1618 * The statement names are set to the names of the
1619 * spaces. The parameter and iterator names of the result are set to those of
1620 * the input, but the scattering dimension names are left unspecified.
1622 CloogUnionDomain *cloog_union_domain_from_isl_set(
1623 __isl_take isl_set *set)
1625 int i;
1626 int nparam;
1627 isl_space *dim;
1628 CloogUnionDomain *ud;
1630 dim = isl_set_get_space(set);
1631 nparam = isl_space_dim(dim, isl_dim_param);
1633 ud = cloog_union_domain_alloc(nparam);
1635 for (i = 0; i < nparam; ++i) {
1636 const char *s = isl_space_get_dim_name(dim, isl_dim_param, i);
1637 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1639 isl_space_free(dim);
1641 ud = add_domain(set, ud);
1643 return ud;
1646 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
1647 static void Euclid(cloog_int_t a, cloog_int_t b,
1648 cloog_int_t *x, cloog_int_t *y, cloog_int_t *g)
1650 cloog_int_t c, d, e, f, tmp;
1652 cloog_int_init(c);
1653 cloog_int_init(d);
1654 cloog_int_init(e);
1655 cloog_int_init(f);
1656 cloog_int_init(tmp);
1657 cloog_int_abs(c, a);
1658 cloog_int_abs(d, b);
1659 cloog_int_set_si(e, 1);
1660 cloog_int_set_si(f, 0);
1661 while (cloog_int_is_pos(d)) {
1662 cloog_int_tdiv_q(tmp, c, d);
1663 cloog_int_mul(tmp, tmp, f);
1664 cloog_int_sub(e, e, tmp);
1665 cloog_int_tdiv_q(tmp, c, d);
1666 cloog_int_mul(tmp, tmp, d);
1667 cloog_int_sub(c, c, tmp);
1668 cloog_int_swap(c, d);
1669 cloog_int_swap(e, f);
1671 cloog_int_set(*g, c);
1672 if (cloog_int_is_zero(a))
1673 cloog_int_set_si(*x, 0);
1674 else if (cloog_int_is_pos(a))
1675 cloog_int_set(*x, e);
1676 else cloog_int_neg(*x, e);
1677 if (cloog_int_is_zero(b))
1678 cloog_int_set_si(*y, 0);
1679 else {
1680 cloog_int_mul(tmp, a, *x);
1681 cloog_int_sub(tmp, c, tmp);
1682 cloog_int_divexact(*y, tmp, b);
1684 cloog_int_clear(c);
1685 cloog_int_clear(d);
1686 cloog_int_clear(e);
1687 cloog_int_clear(f);
1688 cloog_int_clear(tmp);
1691 /* Construct a CloogStride from the given constraint for the given level,
1692 * if possible.
1693 * We first compute the gcd of the coefficients of the existentially
1694 * quantified variables and then remove any common factors it has
1695 * with the coefficient at the given level.
1696 * The result is the value of the stride and if it is not one,
1697 * then it is possible to construct a CloogStride.
1698 * The constraint leading to the stride is stored in the CloogStride
1699 * as well a value (factor) such that the product of this value
1700 * and the coefficient at the given level is equal to -1 modulo the stride.
1702 static CloogStride *construct_stride(isl_constraint *c, int level)
1704 int i, n, sign;
1705 isl_val *v, *m, *gcd, *stride;
1706 isl_val *v_copy, *m_copy, *gcd_copy;
1707 cloog_int_t c_v, c_m, c_gcd, c_stride, c_factor;
1708 CloogStride *s;
1709 isl_ctx *ctx = isl_constraint_get_ctx(c);;
1711 if (!c)
1712 return NULL;
1714 v = isl_constraint_get_coefficient_val(c, isl_dim_set, level - 1);
1716 sign = isl_val_sgn(v);
1717 m = isl_val_abs(v); /* *takes* v. */
1719 gcd = isl_val_int_from_si(ctx, 0);
1720 n = isl_constraint_dim(c, isl_dim_div);
1721 for (i = 0; i < n; ++i) {
1722 v = isl_constraint_get_coefficient_val(c, isl_dim_div, i);
1723 gcd = isl_val_gcd(gcd, v);
1726 m_copy = isl_val_copy(m);
1727 gcd_copy = isl_val_copy(gcd);
1729 v = isl_val_gcd(m, gcd);
1731 v_copy = isl_val_copy(v);
1732 gcd = isl_val_copy(gcd_copy);
1733 stride = isl_val_div(gcd, v);
1735 if (isl_val_is_zero(stride) || isl_val_is_one(stride))
1736 s = NULL;
1737 else {
1738 cloog_int_init(c_m);
1739 cloog_int_init(c_stride);
1740 cloog_int_init(c_v);
1741 cloog_int_init(c_gcd);
1742 cloog_int_init(c_factor);
1744 isl_val_to_cloog_int(m_copy, &c_m);
1745 isl_val_to_cloog_int(stride, &c_stride);
1746 isl_val_to_cloog_int(v_copy, &c_v);
1747 isl_val_to_cloog_int(gcd_copy, &c_gcd);
1749 Euclid(c_m, c_stride, &c_factor, &c_v, &c_gcd);
1750 if (sign > 0)
1751 cloog_int_neg(c_factor, c_factor);
1753 c = isl_constraint_copy(c);
1754 s = cloog_stride_alloc_from_constraint(c_stride,
1755 cloog_constraint_from_isl_constraint(c), c_factor);
1758 cloog_int_clear(c_m);
1759 cloog_int_clear(c_stride);
1760 cloog_int_clear(c_v);
1761 cloog_int_clear(c_gcd);
1762 cloog_int_clear(c_factor);
1765 isl_val_free(stride);
1766 isl_val_free(gcd_copy);
1767 isl_val_free(m_copy);
1768 isl_val_free(v_copy);
1770 return s;
1773 struct cloog_isl_find_stride_data {
1774 int level;
1775 CloogStride *stride;
1778 /* Check if the given constraint can be used to derive
1779 * a stride on the iterator identified by data->level.
1780 * We first check that there are some existentially quantified variables
1781 * and that the coefficient at data->level is non-zero.
1782 * Then we call construct_stride for further checks and the actual
1783 * construction of the CloogStride.
1785 static int find_stride(__isl_take isl_constraint *c, void *user)
1787 struct cloog_isl_find_stride_data *data;
1788 int n;
1789 isl_val *v;
1791 if (!isl_constraint_is_equality(c)) {
1792 isl_constraint_free(c);
1793 return 0;
1796 data = (struct cloog_isl_find_stride_data *)user;
1798 if (data->stride) {
1799 isl_constraint_free(c);
1800 return 0;
1803 n = isl_constraint_dim(c, isl_dim_div);
1804 if (n == 0) {
1805 isl_constraint_free(c);
1806 return 0;
1809 v = isl_constraint_get_coefficient_val(c, isl_dim_set, data->level - 1);
1810 if (!isl_val_is_zero(v))
1811 data->stride = construct_stride(c, data->level);
1813 isl_val_free(v);
1815 isl_constraint_free(c);
1817 return 0;
1820 /* Check if the given list of domains has a common stride on the given level.
1821 * If so, return a pointer to a CloogStride object. If not, return NULL.
1823 * We project out all later variables, take the union and compute
1824 * the affine hull of the union. Then we check the (equality)
1825 * constraints in this affine hull for imposing a stride.
1827 CloogStride *cloog_domain_list_stride(CloogDomainList *list, int level)
1829 struct cloog_isl_find_stride_data data = { level, NULL };
1830 isl_set *set;
1831 isl_basic_set *aff;
1832 int first = level;
1833 int n;
1834 int r;
1836 set = isl_set_from_cloog_domain(list->domain);
1837 n = isl_set_dim(set, isl_dim_set) - first;
1838 set = isl_set_project_out(isl_set_copy(set), isl_dim_set, first, n);
1840 for (list = list->next; list; list = list->next) {
1841 isl_set *set_i = isl_set_from_cloog_domain(list->domain);
1842 n = isl_set_dim(set_i, isl_dim_set) - first;
1843 set_i = isl_set_project_out(isl_set_copy(set_i),
1844 isl_dim_set, first, n);
1845 set = isl_set_union(set, set_i);
1847 aff = isl_set_affine_hull(set);
1849 r = isl_basic_set_foreach_constraint(aff, &find_stride, &data);
1850 assert(r == 0);
1852 isl_basic_set_free(aff);
1854 return data.stride;
1857 struct cloog_can_unroll {
1858 int can_unroll;
1859 int level;
1860 isl_constraint *c;
1861 isl_set *set;
1862 isl_val *n;
1867 * Check if the given lower bound can be used for unrolling
1868 * and, if so, return the unrolling factor/trip count in *v.
1869 * If the lower bound involves any existentially quantified
1870 * variables, we currently punt.
1871 * Otherwise we compute the maximal value of (i - ceil(l) + 1),
1872 * with l the given lower bound and i the iterator identified by level.
1874 static int is_valid_unrolling_lower_bound(struct cloog_can_unroll *ccu,
1875 __isl_keep isl_constraint *c, isl_val **v)
1877 unsigned n_div;
1878 isl_aff *aff;
1879 enum isl_lp_result;
1881 n_div = isl_constraint_dim(c, isl_dim_div);
1882 if (isl_constraint_involves_dims(c, isl_dim_div, 0, n_div))
1883 return 0;
1885 aff = isl_constraint_get_bound(c, isl_dim_set, ccu->level - 1);
1886 aff = isl_aff_ceil(aff);
1887 aff = isl_aff_neg(aff);
1888 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, ccu->level - 1, 1);
1889 *v = isl_set_max_val(ccu->set, aff);
1890 isl_aff_free(aff);
1892 if (!*v || isl_val_is_nan(*v))
1893 cloog_die("Fail to decide about unrolling (cannot find max)");
1895 if (isl_val_is_infty(*v) || isl_val_is_neginfty(*v)){
1896 isl_val_free(*v);
1897 *v = NULL;
1898 return 0;
1901 *v = isl_val_add_ui(*v, 1);
1903 return 1;
1907 /* Check if we can unroll based on the given constraint.
1908 * Only lower bounds can be used.
1909 * Record it if it turns out to be usable and if we haven't recorded
1910 * any other constraint already.
1912 static int constraint_can_unroll(__isl_take isl_constraint *c, void *user)
1914 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1915 isl_val *v;
1916 isl_val *count = NULL;
1918 v = isl_constraint_get_coefficient_val(c, isl_dim_set, ccu->level - 1);
1919 if (isl_val_is_pos(v) &&
1920 is_valid_unrolling_lower_bound(ccu, c, &count) &&
1921 (!ccu->c || (isl_val_lt(count, ccu->n))) ) {
1922 isl_constraint_free(ccu->c);
1923 ccu->c = isl_constraint_copy(c);
1924 if (ccu->n)
1925 isl_val_free(ccu->n);
1926 ccu->n = isl_val_copy(count);
1928 isl_val_free(count);
1929 isl_val_free(v);
1930 isl_constraint_free(c);
1932 return 0;
1936 /* Check if we can unroll the domain at the current level.
1937 * If the domain is a union, we cannot. Otherwise, we check the
1938 * constraints.
1940 static int basic_set_can_unroll(__isl_take isl_basic_set *bset, void *user)
1942 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1943 int r = 0;
1945 if (ccu->c || !ccu->can_unroll)
1946 ccu->can_unroll = 0;
1947 else {
1948 bset = isl_basic_set_remove_redundancies(bset);
1949 r = isl_basic_set_foreach_constraint(bset,
1950 &constraint_can_unroll, ccu);
1952 isl_basic_set_free(bset);
1953 return r;
1957 /* Check if we can unroll the given domain at the given level, and
1958 * if so, return the single lower bound in *lb and an upper bound
1959 * on the number of iterations in *n.
1960 * If we cannot unroll, return 0 and set *lb to NULL.
1962 * We can unroll, if we can identify a lower bound on level
1963 * such that the number of iterations is bounded by a constant.
1965 int cloog_domain_can_unroll(CloogDomain *domain, int level, cloog_int_t *n,
1966 CloogConstraint **lb)
1968 isl_set *set = isl_set_from_cloog_domain(domain);
1969 isl_val *v = cloog_int_to_isl_val(isl_set_get_ctx(set), *n);
1970 struct cloog_can_unroll ccu = { 1, level, NULL, set, v };
1971 int r;
1973 *lb = NULL;
1974 r = isl_set_foreach_basic_set(set, &basic_set_can_unroll, &ccu);
1975 assert(r == 0);
1976 if (!ccu.c)
1977 ccu.can_unroll = 0;
1978 if (!ccu.can_unroll) {
1979 isl_constraint_free(ccu.c);
1980 return 0;
1983 *lb = cloog_constraint_from_isl_constraint(ccu.c);
1985 isl_val_to_cloog_int(ccu.n, n);
1986 /* Note: we have to free ccu.n and not v because v has been
1987 * freed and replaced in ccu during isl_set_foreach_basic_set
1989 isl_val_free(ccu.n);
1990 return ccu.can_unroll;
1994 /* Fix the iterator i at the given level to l + o,
1995 * where l is prescribed by the constraint lb and o is equal to offset.
1996 * In particular, if lb is the constraint
1998 * a i >= f(j)
2000 * then l = ceil(f(j)/a).
2002 CloogDomain *cloog_domain_fixed_offset(CloogDomain *domain,
2003 int level, CloogConstraint *lb, cloog_int_t offset)
2005 isl_aff *aff;
2006 isl_set *set = isl_set_from_cloog_domain(domain);
2007 isl_ctx *ctx = isl_set_get_ctx(set);
2008 isl_constraint *c;
2009 isl_constraint *eq;
2011 c = cloog_constraint_to_isl(lb);
2012 aff = isl_constraint_get_bound(c, isl_dim_set, level - 1);
2013 aff = isl_aff_ceil(aff);
2014 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, level - 1, -1);
2015 aff = isl_aff_add_constant_val(aff, cloog_int_to_isl_val(ctx, offset));
2016 eq = isl_equality_from_aff(aff);
2017 set = isl_set_add_constraint(set, eq);
2019 return cloog_domain_from_isl_set(set);